0x00 写在前面

  • 一开始使用Github提供的Pages服务,后来转到Coding提供的Pages服务。使用Pages服务进行静态网站的部署确实比较方便,但是也会有这样那样的问题,比如网速的问题,我一开始嫌弃Github慢,并且天真的认为换到国内的Coding上面就可以解决这个问题,然而事实却令我无比的失望。而且由于CDN的问题,一些数据不能及时更新。最后,薅了一波阿里云的羊毛,使用阿里云的学生优惠的轻量级服务器,5M的带宽爽的一匹。
  • 问题总是有的,人的懒惰性极大的推动了技术的发展。由于博客迁移到服务器上,那就意味着不能像使用Pages那样直接把build后的代码使用Git进行推送,由Pages服务的供应商来进行自动部署,这让我非常地不爽。我也曾考虑在服务器上面直接进行文章编辑,感觉超级不舒服。所以有一段时间里我都是在本机编辑好然后提交到服务器上,这样极其的麻烦,对于我这样懒惰的人,这种事情是绝对无法接受的。
  • 开始努力的想解决办法,舍友同样被此问题困扰,他最终想的办法是写一个在线编辑的平台。我懒得写,只能另寻他法。巧的是近期的网络安全课设让复现漏洞,我刚好做了几个和Git相关的漏洞(CVE-2017-1000117CVE-2018-17456CVE-2018-11235),这几个漏洞复现下来让我对Git开始有了更加清晰深入的了解,也就是在此时我开始了解Git的Hooks机制,也触发了灵感。Google一波,终于找到了解决办法,也就是今天要和大家探讨的话题——利用Git的Hooks机制实现代码自动部署。
  • 为了避免文件目录或者用户名、服务器系统之类的敏感信息泄露,我就不截图了,文中出现的文件路径和用户名都是我修改过的,请某些同学就不要尝试了,另外如果还是有同学发现了问题,希望你可以积极联系我(anonymking@qq.com)。


0x01 Git服务器部署

  • 我们首先得有一个Git远程项目(废话),在服务器创建一个远程裸仓库:git init --bare test.git
[user@server Dir]$ git --bare init test.git
Initialized empty Git repository in /home/user/Dir/test.git/
[user@server Dir]$ ls
test.git
[user@server Dir]$ ls -a test.git
.  ..  branches  config  description  HEAD  hooks  info  objects  refs
  • 通过上一步我们已经创建了一个空的远程仓库(至于如何搭建git服务器,我就不展开说了,大家执行Google吧,网上有巨量的教程)。
  • 这里说一点,git initgit --bare init创建出来的仓库是的很大的区别的,我们此处适用第二种,我称之为裸(bare)仓库。git --bare init创建出来的项目是看不到代码的,也就是说远程仓库不包含实际项目源文件,而是只记录项目历史版本等各种信息。简单来说,git --bare init的仓库其实其实就相当于git inin创建出来的仓库下面的.git文件夹,从上面ls -a test.git的输出结果便可见一斑。
  • 看明白裸仓库之后,就很容易知道,我们得在服务器初始化一个本地的Git仓库(注意:这里是服务器本地仓库):
[user@server Dir]$ git init test
Initialized empty Git repository in /home/user/Dir/test/.git/
[user@server Dir]$ ls -a test
.  ..  .git
[user@server Dir]$ ls -a test/.git/
.  ..  branches  config  description  HEAD  hooks  info  objects  refs
  • 然后在服务器本地项目中拉取远程项目(此处也就是我们之前创建的裸仓库test.git
  • emmm,实际上在配置博客这个地方主要是使用git clone在把远程项目拉取到本地,上面两部还是主要是想大家理解一下这个过程,因为接下来我们要用,这里要是不太清楚的话接下来不太理解。下面展示一下真实场景(使用git clone进行拉取远程项目)
[user@server Dir]$ ls
test.git
[user@server Dir]$ git clone ./test.git
Cloning into 'test'...
warning: You appear to have cloned an empty repository.
done.
[user@server Dir]$ ls
test  test.git
  • 然后我们要配置Nginx的反向代理(关于Nginx的相关知识此处不涉及,请自行Google),这里只提几句核心配置:
server {
    ...

    location ~ /\.{
      # 防止隐藏文件被访问,虽然在其他地方已经做过防范了,但是安全起见,还是再过滤一下
      deny all;
    }
    location / {
        # root指定上面创建的服务器本地仓库
        root   /home/user/Dir/test/;
        index  index.html index.htm;
    }

    ...
}
  • 到这,Web服务相关的配置已经搭建好了,接下来才是今天的重头戏。


0x02 Git Hooks机制简单说明

  • 和其它版本控制系统一样,Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。(摘抄自Git官方文献)
  • 上面的一段话摘抄自Git官方文献,通俗来讲就是,Git特定功能的实现是使用与其配合的脚本文件来实现的
  • 钩子都被存储在 Git 目录下的 hooks 子目录中。 也即绝大部分项目中的 .git/hooks 。 当你用 git init 初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本。这些脚本除了本身可以被调用外,它们还透露了被触发时所传入的参数。 所有的示例都是 shell 脚本,其中一些还混杂了 Perl 代码,不过,任何正确命名的可执行脚本都可以正常使用 —— 你可以用 Ruby 或 Python,或其它语言编写它们。 这些示例的名字都是以 .sample 结尾,如果你想启用它们,得先移除这个后缀。把一个正确命名且可执行的文件放入 Git 目录下的 hooks 子目录中,即可激活该钩子脚本。 这样一来,它就能被 Git 调用。(摘抄自Git官方文献)
  • 上面这一段话还是来自Git官方文档,它说,一个Git项目所使用的Hook一般都在hooks文件夹中,这些脚本文件的示例文件都是以.sample为后缀,移除其后缀便可以启用他们。我们来简单看一眼:
[user@server Dir]$ ls test.git/hooks/
applypatch-msg.sample      post-update.sample     prepare-commit-msg.sample  pre-receive.sample
commit-msg.sample          pre-applypatch.sample  pre-push.sample            update.sample
fsmonitor-watchman.sample  pre-commit.sample      pre-rebase.sample

[user@server Dir]$ cat test.git/hooks/post-update.sample
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".

exec git update-server-info


0x03 实现代码自动部署流程

  • 我们要使用的Hook是post-receive,该Hook会在整个过程完结以后运行,换句话说,该脚本文件会在整个过程完结以后被执行。(到这,你还没有什么思路的话就太不应该了。)
  • 我们来创建该脚本文件,并赋予其执行权限:
[user@server Dir]$ cd test.git/hooks/
[user@server hooks]$ touch post-receive
[user@server hooks]$ chmod +x post-receive
  • post-receive文件内容如下(当然,你完全可以按照你的思路来写你自己的脚本文件以实现你相应的功能):
#!/bin/sh

# 进入相应目录
cd "/home/user/"
# 移除旧的项目
rm -rf "/home/user/test"
# 拉取远程项目到本地
git clone "/home/user/Dir/test.git" test
# 为了安全 移除.git文件夹
rm -rf "/home/user/test/.git"
  • OK,到这就结束了,你可以在你的PC上面进行提交项目到服务器了,成功提交后服务器就会执行去post-receive脚本文件,下面是一个简单的为本地仓库添加远程仓库并提交代码的过程演示。
[user@PC Blog]$ git remote add origin user@server_ip:/home/user/Dir/test.git
[user@PC Blog]$ git push origin master
  • 懒得画图进行展示整个过程了,困死了(已经凌晨一点了,第一次写这么长的博文,居然花了两个多小时,感觉自己好菜),不多说了,提交代码,睡觉。大家,晚安。


0x04 参考资料