Cao Yi

第十三章 创建和使用 Git 服务节点

⇦上一章 - 首页🏠 - 下一章⇨



按:本章内容可以根据需要选读。

安装 git 的每一个主机(节点)都可以称为一个服务器,这是 git 作为去中心化 VCS 的一个特点。但实际开发中,我们大多还是会创建一个公共节点作为服务器。本章会列举多种创建 git 服务器的方法。

1. 公共 Git 平台

初学者一般无需考虑自建服务器,可以优先考虑公共的 git 平台,如 GitHub, GitLab, Bitbucket 等等,它们都有针对个人用户的免费项目。考虑到流行度 GitHub 是最好的选择,几乎所有的开源项目都会托管到 GitHub 上。前面第九章提到过 GitHub 的使用。GitLab 还可以自己架设在局域网中,深受公司喜欢。Bitbucket 是 Atlassian 旗下的产品,公司用户应该不少。

2. 自建服务器

一般我们选用 Linux 主机作为服务器,因为 Linux 主机很方便开启 SSH 服务。在上一章的「实验准备」一节中,我们已经创建过服务器,这里我们将更详细地说明。

2.1 Server (Linux)

创建一个 git 服务节点,一般有三步:

  1. 安装并开启 SSH 服务
  2. 安装 git
  3. 创建裸库 (bare repository)

以 Ubuntu 为例,安装并开启 SSH 服务(参考)

$ sudo apt update
$ sudo apt install openssh-server

安装 git, 参第三章

$ sudo apt install git

为和新标准保持一致,将默认分支设置为 main

$ git config --global init.defaultBranch main

使用 --bare 参数创建仓库,因为服务器一般无需工作区(Working Directory). 裸库一般以 .git 作为后缀命名

$ git init --bare test.git
Initialized empty Git repository in /home/caoyi/temp/test.git/

2.2 Client

客户端节点对操作系统无所谓,但也需要到官网上下载 git 安装,可参第三章。注意,git 是去中心化的结构,每个节点都是平等的,并没有所谓的服务端和客户端的区分。我们这里区分服务端和客户端只是人为地在业务上的主观划分而已。不论服务端和客户端,它们安装的 git 软件都是一样的。

Git 安装好后,还要进行一些必要的设置,最最基本的设置,就是使用者的姓名和邮箱

$ git config --global user.name  "Cao Yi"
$ git config --global user.email "iridiumcao@gmail.com"

从远程 clone 仓库

$ git clone ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git

为了避免每次和服务器交互都输入密码,可以考虑执行下面的指令以免密登录:

$ ssh-keygen
$ ssh-copy-id caoyi@192.168.0.107

ssh-keygen 生成 ssh key,已经生成过可以忽略,ssh-copy-id 将前面生成的 SSH 公钥传送给服务器。这两个指令输入并回车后,有几处需要确认,直接按回车即可(实验环境,便宜行事)。这两个指令都顺利执行后,将来再通过 SSH 登录192.168.0.107就无需密码了。

3. 镜像服务器

有时因为网络费用或者网络连通性问题,需要一个镜像供大家使用。

场景一:仓库比较大,而且重建仓库的操作比较多,每次都从服务器上获取资源很费流量,需要支付较高费用。

场景二:仓库比较大,而且网络很不稳定很慢,直接 clone 大概率会失败。

以上两种情况都可以考虑在内容建一个镜像节点,平常创建新库时,可以先从镜像上拉取,再从源服务器上获取差量即可。

创建镜像节点的操作很简单,从源库 clone 时加上 --mirror 参数即可,如:

$ git clone --mirror ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git

作为镜像的仓库本身也是裸库,它的更新操作也需要 --bare 参数

$ git --bare fetch

安装后,最好创建一个脚本 /home/caoyi/sandbox/syn_mirror.sh,定期更新,比如10分钟更新一次。

#!/usr/bin/env bash
cd /home/caoyi/temp/test.git
git --bare fetch

Crontab (我们这里设置每10分钟同步一次)

*/10 * * * * /home/caoyi/sandbox/syn_mirror.sh

注意不要向镜像库提交代码,即使提交了,下次同步时会被覆盖掉。我们还可以编写 hook 文件 pre-receive,阻止并提示用户:

#!/usr/bin/env bash

# this is a git server-side hook
# deployment path: {bare repository}/hooks/

echo "Sorry, this is a ready-only mirror server, which does not accept any pushing now."
echo "Please push to the original git server!"
exit 1

对用户来说,从镜像获取代码和从其他节点获取代码是一样的。可以在本地库中设置多个 git URL, 如:

$ git remote add mirror ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git

(假如镜像服务器的地址是 192.168.0.109)

这时本地库就和两个远程库关联:

$ git remote -v
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (fetch)
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (push)
mirror  ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git (fetch)
mirror  ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git (push)

4. 本地仓库

(如果要测试子模块,请勿使用本模式)

有时为了快速测试某些特性,直接在本机创建仓库,并通过文件路径来 clone,例如:

Server:

$ pwd
$ /d/sandbox/temp
$ git init --bare test.git

Client:

$ git clone /d/sandbox/temp/test.git

但这个方式不能使用于子模块 (无论 Windows 还是 Linux 都会出现报错 fatal: transport 'file' not allowed)

$ git clone D:/sandbox/temp/remote/project-main.git
$ git submodule add D:/sandbox/temp/remote/project-sub.git
Cloning into 'D:/sandbox/temp/project-main/project-sub'...
fatal: transport 'file' not allowed
fatal: clone of 'D:/sandbox/temp/remote/project-sub.git' into submodule path 'D:/sandbox/temp/project-main/project-sub' failed

5. 设置远程仓库

多数情况下,我们 clone 好本地仓库之后,接着用就行,本地库和远程库的关联是自动建好的,无需多考虑。但是有些场景下,我们不得不去维护远程库关联。

5.1 查看并添加远程库

我们通过 git clone 创建本地仓库后,本地仓库就自然和远程的仓库建立了联系,可以通过 git remote 指令查看,如:

$ git clone ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git
$ git remote
origin
$ git remote -v
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (fetch)
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (push)

Usually, a local git repository tracks a default remote repository named origin. However, we also needs to work with multiple remote repositories in some cases. 前面讲述镜像库时,就设置了两个远程仓库。

添加远程库使用的指令是 git remote add {remote repo name} {remote repo URL}, 这里的 {remote repo name} 是自定义的。

$ git remote add mirror ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git
$ git remote -v
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (fetch)
origin  ssh://caoyi@192.168.0.107/home/caoyi/temp/test.git (push)
mirror  ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git (fetch)
mirror  ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git (push)

如果想要只得到某个远程库的 URL, 可以用下面的指令

5.2 更新远程库 URL

假如我们的代码服务器的 IP 不是固定的,下次重启机器后变成 192.168.0.109,我们可以通过下面的指令更新 git URL:

$ git remote set-url origin ssh://caoyi@192.168.0.109/home/caoyi/temp/test.git

在实际开发中,用作代码服务器的主机,一般要求设置静态 IP,此处仅为举例说明而已。

如果代码服务器的仓库路径发生变化,仓库的 git URL 也会发生变化,假如现在服务器上的仓库路径从 /home/caoyi/temp/test.git 变成 /codebase/test.git,则本地仓库应该进行如下设置

$ git remote set-url origin ssh://caoyi@192.168.0.109/codebase/test.git

通常服务器节点不宜暴露过长的路径,我们往往使用一个简短的软连接路径和实际路径关联起来,用户使用包含软连接的路径即可。

5.3 解除远程库关联

如果想要解除和某个库的关联,可以使用 git remote rm {remote repo name},如

$ git remote rm mirror

5.4 多远程库下的本地库操作

如果一个本地库关联了多个远程库,则它在执行 pullpush 等指令时,不能省略库名,比如

$ git pull mirror {branch name}

(指令中必须明确写出是从哪个库中 pull 的,比如 mirrororigin)

从远程拉取分支时,也要明确指明从哪个仓库拉取 (git switch/checkout --track {remote repo name}/{branch name}):

$ git switch --track origin/branch_hello

$ git checkout --track origin/branch_hello

如果直接执行 git switch branch_hello 会失败,因为 git 不知道从哪个远程库中取。

5.5 git remote 指令总结


推荐阅读


⇦上一章 - 首页🏠 - 下一章⇨