前言
【裸仓库】指的是使用 git init --bare
命令得到的仓库,是对这种操作结果的一种直译,这个词对于刚接触 git 软件的小伙伴来说可能是第一次听说,而我也是最近实际操作了几次才渐渐理解,下面解释一下什么是裸仓库,以及为什么要使用它,有理解不对的地方还请大家指正。
普通库和裸仓库
普通库
在解释裸仓库之前,还是先来看看 git init
命令创建一个普通仓库的目录结构:
1 | [root@VM-0-3-centos data]# git init simple |
通过上述命令操作后可以看到,git init simple
操作之后,创建了一个名为 simple
的库,simple
目录下还有一个 .git
子目录,其中包含了git系统常用的文件,在 .git
目录外是我们的工作区,可以存放我们库中待更新的文件,修改之后可以通过 git add
,git commit
等命令更新 .git
中的内容,简单来说普通库就是在工作目录 simple
中还包括一个 .git
目录,下面添加一个文件试试。
1 | [root@VM-0-3-centos simple]# git add README.md |
添加文件之后,.git
目录中的内容发生了变化,多了3个新的object。
裸仓库
还是先从目录结构入手,我们使用 git init --bare
命令创建一个裸仓库,目录结构如下:
1 | [root@VM-0-3-centos data]# git init --bare bare.git |
从目录结构来看裸仓库和普通库很像,但是仔细对比你会发现,这个裸仓库相比普通库少了一层目录,库目录 bare.git
内直接就是之前普通库 .git
目录下的内容,也就是说在 git
目录外层没有了工作目录来进行文件的增删改操作,那么我们仿照普通库操作在这个目录下提交一个文件会怎样呢?
1 | [root@VM-0-3-centos data]# cd bare.git/ |
通过操作发现这个裸仓库不允许增删改库内的文件,甚至连 git status
这种命令都无法使用,统一提示了 fatal: This operation must be run in a work tree
这句话,告诉用户这些命令都必须在工作区内操作,既然不能修改,那么这个裸仓库就是“只读”的,那么它还有什么用呢?
虽然裸仓库不允许直接修改,但是可以作为服务端远程仓库,在本地克隆这个远程仓库之后再进行修改,这也是最常见的应用方式,总结来说,普通库和裸仓库的区别就是:普通库拥有工作目录,并且工作目录中可以存放正常编辑和提交的文件,而裸库只存放这些文件的commit记录,不允许用户直接在上面进行各种git操作。
使用裸仓库
前面提到裸仓库不能直接修改,但是我们可以采取修改克隆后库文件的方式达到更新的目的,下面列举两种常见的方式:
使用 git remote add 方式关联
这种方式需要我们先在本地初始化一个普通库,再使用 git remote add
命令建立关联(PowerShell命令行操作,git命令是相同的):
1 | PS-Win D:\data\maingit\test> git init barebyremote |
使用 git clone 直接克隆
使用克隆方式时,按照普通库来操作就可以(PowerShell命令行操作,git命令是相同的):
1 | PS-Win D:\data\maingit\test> git clone root@82.156.125.196:/data/bare.git barebyclone |
为什么要使用裸仓库
既然裸仓库相比于普通库只是少了工作目录,那么我们直接用普通库作为远程仓库可不可以呢?结论是可以,但是不建议,我们来实际操作一下,利用刚刚的建立的 simple
作为远端库,我们在本地clone后修改,再上传看看会遇到什么问题。
1 | PS-Win D:\data\maingit\test> git clone root@82.156.125.196:/data/simple simple |
克隆之后正常的修改和提交都没有问题,但是 git push
的时候报错,原因提示 ! [remote rejected] master -> master (branch is currently checked out)
,提示当前的 master
分支是检出状态,不允许直接推送。
仔细想想就会有些思路,普通库实际上包含两份数据的,一份在 .git
目录中以object形式存在,一份在工作目录中以源文件形式存在,我们每次使用 git
命令,可以保证工作目录内文件和 .git
目录数据是一致的,但是如果将普通库作为远端时,在下游提交数据时,远端库中的 .git
目录会直接更新,但是工作区却不知道此时谁在用,不能直接更新覆盖,这就造成了数据不一致的情况。
如果非得使用普通库作为服务端仓库,那么可以参照上面报错的建议,在采用额外方式保证一致性的同时,修改服务端库的 receive.denyCurrentBranch
这个git配置项,或者将服务端分支切换到一个无人使用的分支上,这样下游端就可以直接推送了。
1 | [root@VM-0-3-centos data]# cd simple/ |
1 | PS-Win D:\data\maingit\test\simple> pwd |
自动化部署
利用 post-receive
进行自动化部署的原理就是,git
本身提供了一些脚本接口,在某些 git
操作发生时,会调用预定脚本执行命令,相当于给 git
用户开放了接口,我们可以修改 post-receive
脚本,在修改提交后自动部署最新内容,进一步实现自动化集成。
因为前面已经介绍了很多有关裸仓库的知识,接下来我只叙述操作步骤,看了之前的介绍,这部分内容应该没什么难度了。
需求
服务端建立裸仓库,在接收到新的提交时,自动将项目部署到/data/publish/game
目录下
操作步骤
服务端远端操作
建立裸仓库 /data/repo/game.git
,对应部署目录是 /data/publish/game
1 | [root@VM-0-3-centos data]# mkdir -p /data/repo |
新建 /data/repo/game.git/hooks/post-receive
脚本,可以拷贝 post-receive.sample
进行修改,脚本内编写内容如下:
1 | # 指定部署目录 |
客户端本地操作
本地项目普通库目录结构如下,启动脚本为 start.sh
:
1 | albert@home-pc MINGW64 /d/data/maingit/test/game (master) |
与远端裸仓库建立关联
1 | albert@home-pc MINGW64 /d/data/maingit/test/game (master) |
至此自动化部署环境已建立,当本地 game 仓库推送更新时,远端服务器会自动更新部署
快速回顾
文中主要命令收于此节,方便自己后期快速查找操作
- 服务端远程新建裸仓库
1 | cd /data/repo |
- 本地库与远端库建立关联
1 | git remote add origin root@82.156.125.196:/data/repo/game.git |
- 新建或修改
hooks
目录下post-receive
脚本
1 | DIR=/data/publish/game |
总结
- 裸仓库是一个只包含提交记录,没有工作目录的仓库,适合用来做服务端远程仓库
- 裸仓库不能直接在仓库中执行修改文件的git命令,可以在客户端克隆之后修改之后再进行提交
- 自动化部署利用了git服务器提供的脚本接口,当新的推送达到时会调用
post-receive
脚本 - 配置自动化部署环境时需要注意,如果没有配置ssh免密码登陆,需要在push代码的时候输入密码
- 另外自动化部署时要注意各个文件及目录的权限,因为要运行脚本,要保证推送用户有足够的运行权限
每个人都有自己的选择,很多看似突如其来的决定,往往都是深思熟虑后的结果,每个人在自己的旅途中不断的分类、选择、分类、选择,无法逃离的坚持到最后一刻~
2022-6-12 20:19:30