前面我们介绍的都是和本地主机上Git仓库相关的操作,然而前面我们介绍过,Git是一个分布式版本控制系统,同一个Git仓库其实可以分布到不同的主机上,这样就产生了本地仓库和远程仓库的概念,Git工具针对远程仓库,也提供了相应的操作命令。这篇笔记我们介绍Git远程仓库的搭建,以及和远程仓库的交互命令。
我们都知道Github,它是程序员都很熟悉的代码托管平台,我们可以在Github上免费建立代码仓库并托管代码,这其实就是一种远程仓库。Github平台本身不是开源的,如果我们打算自己搭建一个这样的代码托管平台,则可以选择Gitlab(社区版)和Gitea。其中,Gitlab是一个功能非常完善的代码托管平台,能够满足大型企业软件项目的代码托管需求,当然其对服务器硬件资源的需求也非常高;而Gitea是一个Go语言编写的轻量级项目,它可以轻易部署到低配置的主机甚至树莓派上,非常适合个人和小型团队使用。
然而,Github、Gitlab、Gitea这些代码托管系统底层还是基于Git工具的,展开讨论这些代码托管平台超出了本篇笔记的范围,我们这里直接介绍如何基于Git工具搭建一个最简单的远程Git仓库。
我们首先需要在主机上安装Git命令行工具。
apt install git
Git远程仓库可以基于SSH协议拉取和推送代码,它可以使用Linux系统配置的用户进行认证和鉴权,我们也采用这种方式。不过为了安全起见,我们不直接使用root用户或是当前Linux登录用户作为Git操作的用户,而是新创建一个叫git
的用户。
adduser git
出于安全起见,我们应该禁止git
用户通过SSH登入系统Shell,这里我们修改/etc/passwd
,把git
用户的默认Shell修改为git-shell
(其实这是个无法登陆的Shell,一登录就会退出)。
git:x:1000:1000:,,,:/home/git:/usr/bin/git-shell
然后我们进入git
用户的家目录,添加允许SSH连接的公钥。
su git && mkdir ~/.ssh && touch ~/.ssh/authorized_keys
接下来我们把客户端的公钥复制到服务器的authorized_keys
里,如果添加多个公钥,一行写一个即可。下图是Windows的情况,在Linux下SSH公钥在~/.ssh
下。
接下来我们就可以创建远程仓库了,假如我们想要把远程仓库文件夹放在/srv
下,使用root权限以下操作可以建立一个远程仓库并赋权给git
用户。
cd /srv
git init --bare sample.git
chown -R git:git sample.git
这样服务器就配置完成了,在客户端我们直接clone仓库即可。
git clone [用户名]@[服务器IP]:[远程仓库路径]
命令的使用方式例如git clone git@192.168.1.100:/srv/sample.git
。
实际开发中,其实我们还是倾向于使用代码托管平台,而向上面这样搭建Git远程仓库是比较少用的,因此对其了解即可。
如果没有SSH密钥,我们可以使用ssh-keygen
命令创建一个。
ssh-keygen -t rsa
clone命令用于克隆远程仓库,它可以理解为将远程仓库内容“下载”到本地并建立本地和远程仓库的关联以便后续操作,下面是一个例子。
git clone git@gitee.com:gacfox/demo.git
注:这里由于我的远程仓库是空的,因此有一个警告,不过这并不影响后续操作。
clone命令默认只会拉取主分支的提交(即master分支),其它远程分支也会被记录到本地仓库,只不过其它分支上的提交没有被真正拉取,我们可以使用checkout命令切换到其它分支上,然后再使用pull命令拉取内容。
此外,上面的Git远程仓库地址git@gitee.com:gacfox/demo.git
是SSH协议的,克隆时我们也可以使用HTTPS协议,例如https://gitee.com/gacfox/demo.git
。不过HTTPS协议需要输入用户名和密码,而SSH协议则通过公钥认证,后者更加方便,但有些企业会出于安全原因禁用SSH协议连接,因此这两种方案都非常常用。
有时我们已经有一个本地仓库,现在想要和远程新建的空仓库关联起来,这可以使用git remote add
操作。
git remote add origin git@gitee.com:gacfox/demo.git
其中origin
是远程仓库的默认别名,一个本地仓库可以关联多个远程仓库,和远程仓库交互时需要通过这个别名区分。一般来说,如果我们只有一个默认远程仓库,都约定将其起名为origin
。
fetch命令用于从远程仓库下载所有最新的提交、分支、标签等信息,但不会自动将这些更改合并到当前分支。它只是在本地更新远程追踪分支的状态。
git fetch origin
当执行fetch命令时,Git会从远程仓库获取所有分支的最新提交,并更新这些分支的远程追踪分支(如origin/dev
),即便这些分支在本地还没有被创建或没有被检出。
如果本地已经有与远程对应的分支,比如dev
分支,fetch命令不会将远程的origin/dev
分支的更新直接应用到你的本地dev
分支,它需要手动进行合并。手动合并的一种方式如下,它将远程追踪分支的内容合并到本地分支。
git checkout dev && git merge origin/dev
此外,我们也可以切换到目标分支后,使用下面的pull命令实现合并。
pull命令类似于fetch和merge的组合操作,它从远程仓库拉取最新的提交,并将这些更改自动合并到当前分支。即如果远程分支有更新,pull命令会尝试直接将更新合并到你当前的分支。下面命令我们从远程仓库拉取dev
分支的最新提交。
git checkout dev && git pull origin dev
如果不指定任何参数直接运行git pull
,默认会从远程仓库中当前分支的远程追踪分支拉取更新,并尝试将其合并到当前分支。
pull
由于包含合并操作,因此如果远程仓库的提交和本地仓库的提交有冲突,需要手动解决冲突。
push命令用于推送本地仓库的提交到远程仓库,下面是例子我们推送本地仓库的master
分支到远程仓库。
git push origin master
如果远程仓库中不存在master
分支,push时会自动在远程仓库创建同名的分支。此外,如果远程仓库中的内容在推送时存在冲突,push操作会失败,这需要我们先使用fetch或pull命令拉取远程仓库的更新,在本地解决冲突后再推送。