git裸仓库到底是怎么样的——实践出真知

用服务器部署Git,探究裸仓库——实践出真知

前些天,给阿里云服务器部署 Hexo 框架写点 Blog,受一篇博客 在阿里云上搭建 Hexo 博客详细流程 的启发,顺手写下了本篇 Blog。

开篇,让我们看一个代码片段:

cd /var/repo
git init --bare blog.git(同步目录名)
cd blog.git/hooks/
vim post-receive
#写入以下内容
#!/bin/sh
git --work-tree=/path/to/www --git-dir=/var/repo/blog.git checkout -f

没有 Git 基础的同学可能会有很多疑问:git init --bare的结果是什么?为什么需要--bare参数?blog.git是啥?post-receive 这个文件有啥用?git 参数 --work-tree--git-dir 又是什么意思?checkout有什么功能?-f参数又是什么?

基础方面建议参考资料:Pro Git 第二版,《git 权威指南》

有了对基本命令意思的了解,让我们直接进入实践环节,看看如何将 Git 完美部署到服务器上。

所有协议均采用 ssh 协议,两台云服务器 A 和 B,服务器 Git 版本均为 2.25.1,Ubuntu 操作环境。(没有两个服务器,可以用一个服务器 + 本地 或 两个本地目录替代

双实库,B 克隆 A

主体 A:

cd /home/repo
git init testOne
git config --global user.name "name"
git config --global user.email "a@b.c"
git commit --allow-empty -m "测试 1"
git log --oneline

主体 A 中:

克隆体 B:

cd /home/repoT
git clone ssh://user@host/home/repo/testOne

注意,实体的克隆体 B 无法将任何改变git push到 A 中。

B 可以从 A 中拉取:

克隆体 B :

主体 A Push 到克隆体 B?

注意 1:push 需要设置一个【远程 git】角色,这个角色是通过git remote add <角色名称> <角色地址>这条命令实现的。在这里,名称我们可以叫:orgin,地址可以用 ssh 协议链接

注意 2:因为我们用的是 ssh 协议,所以 要设置好 git 仓库的权限与所有者,否则会出现错误。

主体 A:

git remote add orgin ssh://user@host/home/repoT/testOne
# 做一个【空提交】,代码在下图

主体 A 中:

很好理解,github 上面有你喜欢的开源项目,你想要为它贡献代码,于是将其 clone 到你的账户下。但如果允许你账户下的克隆体 push,就会导致开源项目历史混乱,且不值得维护。可如何贡献你的代码呢?

这正是我们接下来要讨论的,双向 Pull(Pull Request)。

主体与克隆体之间,相互 Pull

注意:克隆体 B 一定能 Pull 主体 A 的最新更改,因为在 clone 之后,如下图,git 就自动会有一个可以 fetch 主体 A 的“角色”(这也解释了前文说到 B 无法 push 到 A 时,为什么没谈“角色”建立的问题)

那 A 能 Pull B 吗?

克隆体 B:

git commit --allow-empty -m "B 发生了改变"
git log --oneline

主体 A:

# 已默认 remote add
git pull

也就是 A 与 B 可以相互 Pull。实际上,GitHub 中的 Pull Request 也是让开源项目主动 Pull 个体代码的意思。

对等间实体的关系下,如何应用到我们服务器部署 Git 呢?也许只有一种方法,就是 让服务器主动 Pull 我们的代码而非我们主动 Push 到服务器上。但正如我们能主动设置 git 强行 Push,这样的 Pull 方式反倒失去了 Pull 的本意。 不如一开始使用【裸库】:git init --bare 来让一切回到正轨。

A 服务器裸库初始化,B 与主机为克隆

我让主机参与了进来,是为了体现主机与 B Push 的效果。

A:

git init --bare testTwo.git #testTwo.git 是一个目录的名称,不是什么文件

主动更新

我们先不在 A 上面添加文件,按参考书惯例,先用主机把这个裸库 clone 下来。

主机:

git clone ssh://user@host/home/repo/testTwo.git testTwoWin

Clone 有警告不要紧,关键在于 Clone 后的东西。从目录结构上看,我们 Clone 的是一个完整的库,.git 目录下没有记录历史,工作目录空无一物,更没有裸库 A 的目录结构。

主机:

git commit --allow-empty -m "主机有更改"
git push

此时 A 中:

【注意】:这里允许 push 之后,就已经实现了 git 服务器的被动更新,服务端不用写定时任务定时 Pull 了。

上传文件到裸库?

主机再添加一个文件:

vim a.txt #测试文件
git add .
git commit -m "主机添加了一个文件"
git push

可以看到,在主机 push 一个文件 a.txt 时,由于没有【工作目录】,A 只接受了新的 git 提交历史。

要是一般的 git 服务器配置,那这篇文章就已经结束了,但是我需要的是将 Hexo 框架通过 Git 部署到服务器上。服务器 git 没有设置工作目录怎么办?

获取工作目录的解决办法

使裸库带工作目录? 奥秘在 git --work-tree=/path/to/www --git-dir=/var/repo/blog.git checkout -f这句话
git 命令可带参数:work-tree 与 git-dir,前者指定工作目录的位置,后者指定 .git 目录(也就是我们的裸库)。

那只带这两参数就行了吗?非也,别忘了后面那个命令 cheakout -f

非常有意思,checkout -f 在未指定分支下居然是个【无改变】命令,而 这个命令也是我目前遇到的唯一一个能刷新工作目录的命令 ,再结合前面的–work-tree 参数,我们就能被 Clone 的同时,被 Push,且能获取 Push 的工作目录

【注意】:如果没改变 commit 历史,直接用git push不会触发 post-receive 这个 Hook

最后

服务器搭建不只是完成 git 部分就够了。

  1. lmnp 下载安装:下载地址
cd /home/download
wget http://soft.vpser.net/lnmp/lnmp1.8-full.tar.gz
tar zxf lnmp1.8-full.tar.gz
cd lnmp1.8-full/
./install lnmp

注意:Mysql 那些都不需要

  1. vhost 添加