持續(xù)集成的一個(gè)環(huán)節(jié)就是提交代碼后,能即刻部署到測試環(huán)境下伟桅,以運(yùn)行各類測試用例。
本文使用 git hook 即可做到代碼的簡易部署叽掘。我們以一個(gè)網(wǎng)站為例楣铁。
解決方案的思路
你的網(wǎng)站代碼在你本地 git 庫里,你把代碼 push 到遠(yuǎn)程 git 庫里(你的 Web 服務(wù)器)够掠,通過 post-receive hook 部署到 document root 網(wǎng)站目錄下民褂。
示例
原創(chuàng)文章請參見 Using Git to manage a web site茄菊,作者 menon-sen 2008年的一篇文章疯潭,致敬赊堪!
本文有改動(dòng),以用戶 /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:設(shè)置 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
- 請務(wù)必加上執(zhí)行權(quán)限哭廉,否則不會(huì)執(zhí)行;
hook 設(shè)置好后相叁,執(zhí)行以下任一命令查看效果:
hooks/post-receive
遵绰,. hooks/post-receive
,source hooks/post-receive
- 請確保 GIT_WORK_TREE 所指向的目錄存在增淹,否則會(huì)報(bào)告錯(cuò)誤 “fatal: This operation must be run in a work tree”椿访。
網(wǎng)站目錄權(quán)限
- 網(wǎng)站目錄
post-receive 腳本中設(shè)置的 GIT_WORK_TREE 變量,就是網(wǎng)站目錄:
$ mkdir -p /home/app/wph/web/
- 目錄權(quán)限
假設(shè)使用 nginx HTTP Server虑润,網(wǎng)站目錄一般都設(shè)置為 nginx:nginx成玫。可以把 michael 用戶加到 nginx 組內(nèi)(修改 /etc/group)拳喻,網(wǎng)站目錄 chmod 設(shè)置為同組可寫哭当。
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 組钦勘,更方便理解⊙乔祝或者直接設(shè)置為 michael:michael 也可以彻采。
The local repository:和 remote 關(guān)聯(lián)
$ cd ~/wph/web
$ git remote add xweb ssh://192.168.99.236/home/michael/wph/web.git
$ git push xweb +master:refs/heads/master
至此,網(wǎng)站目錄下就有了 master 分支的完整的文件副本捌归,但不包含 .git metadata(這個(gè)很好颊亮,類似于 svn export 了)。以后陨溅,你只要 git push xweb终惑,在推送到遠(yuǎn)程庫的同時(shí),你的網(wǎng)站目錄就得到了更新门扇。
注:
- git remote: Manage set of tracked repositories
- 假如你本地庫是從另外一個(gè)遠(yuǎn)程庫復(fù)制來的雹有,簽出在不同的分支下(不在 master 下),則
git push xweb +master:refs/heads/master
時(shí)臼寄,會(huì)報(bào)錯(cuò)霸奕,調(diào)整一下命令參數(shù)即可,比如:git push xweb +v0.3:refs/heads/v0.3
吉拳。 - "Error: EPERM: operation not permitted, chmod ..." 錯(cuò)誤
這個(gè)錯(cuò)誤有時(shí)會(huì)發(fā)生在 gulp 下生成的新目錄文件身上质帅。網(wǎng)站目錄設(shè)置為 michael:nginx 即可; - pull/push from multiple remote locations;
git remote set-url origin --add --push <a remote>
git remote set-url origin --add --push <another remote>
這樣你就可以同時(shí)推送到多個(gè)遠(yuǎn)程庫了煤惩,而不必一個(gè)一個(gè)推送嫉嘀。
git push <repository> [<refspec>…?]
- <refspec>…?
Specify what destination ref to update with what source object. The format of a <refspec> parameter is an optional plus +, followed by the source object <src>, followed by a colon :, followed by the destination ref <dst>.
The <src> 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 <dst> tells which ref on the remote side is updated with this push. The object referenced by <src> is used to update the <dst> reference on the remote side. By having the optional leading +, you can tell Git to update the <dst> 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`:+<src>:<dst>;省略 `:<dst>`魄揉,則表示推送到遠(yuǎn)程同名 ref剪侮;
- `+`表示強(qiáng)制推送,allow non-fast-forward updates洛退;
- 為了簡單起見瓣俯,通常 +v0.3:master 即可,即將本地 v0.3 推送到遠(yuǎn)程 master(這樣遠(yuǎn)程簽出 master 到站點(diǎn)目錄兵怯,而不必每次都修改簽出目錄)彩匕;
post-receive 示例(發(fā)布指定分支)
#!/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 版)