按:本章内容可以根据需要选读。
安装 git 的每一个主机(节点)都可以称为一个服务器,这是 git 作为去中心化 VCS 的一个特点。但实际开发中,我们大多还是会创建一个公共节点作为服务器。本章会列举多种创建 git 服务器的方法。
初学者一般无需考虑自建服务器,可以优先考虑公共的 git 平台,如 GitHub, GitLab, Bitbucket 等等,它们都有针对个人用户的免费项目。考虑到流行度 GitHub 是最好的选择,几乎所有的开源项目都会托管到 GitHub 上。前面第九章提到过 GitHub 的使用。GitLab 还可以自己架设在局域网中,深受公司喜欢。Bitbucket 是 Atlassian 旗下的产品,公司用户应该不少。
一般我们选用 Linux 主机作为服务器,因为 Linux 主机很方便开启 SSH 服务。在上一章的「实验准备」一节中,我们已经创建过服务器,这里我们将更详细地说明。
创建一个 git 服务节点,一般有三步:
以 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/
客户端节点对操作系统无所谓,但也需要到官网上下载 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就无需密码了。
有时因为网络费用或者网络连通性问题,需要一个镜像供大家使用。
场景一:仓库比较大,而且重建仓库的操作比较多,每次都从服务器上获取资源很费流量,需要支付较高费用。
场景二:仓库比较大,而且网络很不稳定很慢,直接 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)
(如果要测试子模块,请勿使用本模式)
有时为了快速测试某些特性,直接在本机创建仓库,并通过文件路径来 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
多数情况下,我们 clone 好本地仓库之后,接着用就行,本地库和远程库的关联是自动建好的,无需多考虑。但是有些场景下,我们不得不去维护远程库关联。
我们通过 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)
git remote
查看远程仓库,一般默认的就是 origingit remote -v
查看远程仓库的详细信息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, 可以用下面的指令
git config --get remote.origin.url
git remote get-url origin
假如我们的代码服务器的 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
通常服务器节点不宜暴露过长的路径,我们往往使用一个简短的软连接路径和实际路径关联起来,用户使用包含软连接的路径即可。
如果想要解除和某个库的关联,可以使用 git remote rm {remote repo name}
,如
$ git remote rm mirror
如果一个本地库关联了多个远程库,则它在执行 pull
或 push
等指令时,不能省略库名,比如
$ git pull mirror {branch name}
(指令中必须明确写出是从哪个库中 pull
的,比如 mirror
或 origin
)
从远程拉取分支时,也要明确指明从哪个仓库拉取 (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 不知道从哪个远程库中取。
git remote
指令总结git remote
简明显示当前库关联的远程库,只显示名称git remote -v
详细显示当前库关联的远程库,除了名称,还显示 git URLgit remote add {remote repo name} {git URL}
给当前库增加一个关联的远程库git remote rm {remote repo name}
将本地项目和某个远程仓库解除关联git remote prune origin
同步远程分支信息到本地,远程已经删除分支,本地的引用也会删除。git push -u {remote rempo name} {branch name}
推送到具体某 branch 到某库并建立关联,之后推送可以不加 -u
参数推荐阅读