持续集成 の 使用 git hook 部署代码

持续集成的一个环节就是提交代码后,能即刻部署到测试环境下,以运行各类测试用例。

本文使用 git hook 即可做到代码的简易部署。我们以一个网站为例。

解决方案的思路

你的网站代码在你本地 git 库里,你把代码 push 到远程 git 库里(你的 Web 服务器),通过 post-receive hook 部署到 document root 网站目录下。

示例

原创文章请参见 Using Git to manage a web site,作者 menon-sen 2008年的一篇文章,致敬!
本文有改动,以用户 /home/michael 为例。

The local repository:建库
$ cd
$ mkdir wph/web
$ cd wph/web
$ git init
Initialized empty Git repository in /home/michael/wph/web.git/
$ echo 'Hello, world!' > index.html
$ git add index.html
$ git commit -q -m "The humble beginnings of my web site."
The remote repository:建库
$ cd
$ mkdir -p wph/web.git
$ cd wph/web.git
$ git init --bare
Initialized empty Git repository in /home/michael/wph/web.git/
The remote repository:设置 hook
$ cd ~/wph/web.git

# 编辑 hook 脚本
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/home/app/wph/web git checkout -q -f

$ chmod +x hooks/post-receive
  • 请务必加上执行权限,否则不会执行;

hook 设置好后,执行以下任一命令查看效果:
hooks/post-receive. hooks/post-receivesource hooks/post-receive

  • 请确保 GIT_WORK_TREE 所指向的目录存在,否则会报告错误 “fatal: This operation must be run in a work tree”。
网站目录权限
  • 网站目录
    post-receive 脚本中设置的 GIT_WORK_TREE 变量,就是网站目录:
    $ mkdir -p /home/app/wph/web/
  • 目录权限
    假设使用 nginx HTTP Server,网站目录一般都设置为 nginx:nginx。可以把 michael 用户加到 nginx 组内(修改 /etc/group),网站目录 chmod 设置为同组可写。
chown -R nginx:nginx /home/app/wph/web/
chmod -R g+w /home/app/wph/web/

或者
chown -R michael:nginx /home/app/wph/web/,michael 作为 owner,用户 nginx 属于 nginx 组,更方便理解。或者直接设置为 michael:michael 也可以。

The local repository:和 remote 关联
$ cd ~/wph/web
$ git remote add xweb ssh://192.168.99.236/home/michael/wph/web.git
$ git push xweb +master:refs/heads/master

至此,网站目录下就有了 master 分支的完整的文件副本,但不包含 .git metadata(这个很好,类似于 svn export 了)。以后,你只要 git push xweb,在推送到远程库的同时,你的网站目录就得到了更新。

注:

  1. git remote: Manage set of tracked repositories
  2. 假如你本地库是从另外一个远程库复制来的,签出在不同的分支下(不在 master 下),则 git push xweb +master:refs/heads/master 时,会报错,调整一下命令参数即可,比如:git push xweb +v0.3:refs/heads/v0.3
  3. "Error: EPERM: operation not permitted, chmod ..." 错误
    这个错误有时会发生在 gulp 下生成的新目录文件身上。网站目录设置为 michael:nginx 即可;
  4. pull/push from multiple remote locations;
git remote set-url origin --add --push 
git remote set-url origin --add --push 

这样你就可以同时推送到多个远程库了,而不必一个一个推送。

git push […​]

  • …​

Specify what destination ref to update with what source object. The format of a parameter is an optional plus +, followed by the source object , followed by a colon :, followed by the destination ref .

The is often the name of the branch you would want to push, but it can be any arbitrary "SHA-1 expression", such as master~4 or HEAD.

The tells which ref on the remote side is updated with this push. The object referenced by is used to update the reference on the remote side. By having the optional leading +, you can tell Git to update the ref even if it is not allowed by default.

To force a push to only one branch, use a + in front of the refspec to push (e.g git push origin +master to force a push to the master branch)

  • 示例
git remote add prod-web ssh://192.168.99.236/home/git/wph/web.git
git push prod-web +v0.3:refs/heads/v0.3
- `+v0.3:refs/heads/v0.3`:+:;省略 `:`,则表示推送到远程同名 ref;
- `+`表示强制推送,allow non-fast-forward updates;
- 为了简单起见,通常 +v0.3:master 即可,即将本地 v0.3 推送到远程 master(这样远程签出 master 到站点目录,而不必每次都修改签出目录);

post-receive 示例(发布指定分支)

#!/bin/bash

target_branch="production"
working_tree="PATH_TO_DEPLOY"

while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    if [ -n "$branch" ] && [ "$target_branch" == "$branch" ]; then
    
       GIT_WORK_TREE=$working_tree git checkout $target_branch -f
       NOW=$(date +"%Y%m%d%H%M%S")
       git tag release_$NOW $target_branch
    
       echo "   /==============================="
       echo "   | DEPLOYMENT COMPLETED"
       echo "   | Target branch: $target_branch"
       echo "   | Target folder: $working_tree"
       echo "   | Tag name     : release_$NOW"
       echo "   \=============================="
    fi
done

备注

  • Git Hooks 入门
  • 在 web/ 下 m(mobile 版)、www(pc 版)

你可能感兴趣的:(持续集成 の 使用 git hook 部署代码)