商业转载请联系作者获得授权,非商业转载请注明出处。
作者:吴中杰
链接:http://zhuanlan.zhihu.com/airbnb/19757507
来源:知乎
不知大家在做一些需要服务器的小项目的时候都是怎么部署代码的?我之前在Heroku的时候就觉得他家的代码部署方法及其方便,基本上就是
heroku apps:create my_app
git push heroku master
然后就一路帮你部署到heroku的平台。绝对是2分钟上线一个Rails网站。
于是我这两天就在研究如何用git push部署代码,发现网上的大部分解决方案都是基于git checkout的。我不太喜欢这个方法,因为用这个方法push后,真正的代码属于漂浮的状态,当你运行git status的时候会发现那些新加的代码依然处于unstaged状态。
我下面要介绍的是基于git reset --hard的push-to-deploy设置方案
首先你需要一个服务器,这个服务器可以是你家里的电脑也可以是云端的服务器。你必须可以顺利ssh进去。至于怎么ssh,这不是本文要讨论的内容(大家可以学习ssh-keygen、authorized_keys、man ssh-config的相关内容)。
假如你能顺利的ssh进你的服务器如
ssh ubuntu@myserver.com
那么要做的事情如下
设置文件夹
进入本地git文件夹,然后将代码push到一个远端新建的裸代码库。
cd local_git_code
git remote add stg ubuntu@myserver.com:my_repo
ssh ubuntu@myserver.com 'cd ~ && git init --bare my_repo;'
什么是裸代码库?基本上就是那些github之类的网站存储你的代码的形式。这样的代码库只有历史记录和索引,没有实际以文件形式存在的代码。那些代码都以二进制的形式存在git自己的数据库里。
有了代码库以后就可以设置自己的自动部署挂钩了。这个挂钩本质是一个脚本,当这个文件在repo/hooks/文件夹内,名字为post-receive并且ubuntu的x属性(可执行)为真的时候,git会在收到push后执行它。
于是你就应该将下面这个脚本稍加修改放到本地的git工作文件夹中,可以取名post-receive.hook。注意,这个文件必须为可执行状态,可以用
ls -l .
查看。可以使用
chmod u+x post-receive.hook
保证其可执行型。
#!/bin/sh
# This file is to be used by git repo on server
# It should be a file called hooks/post-receive in the bare git repo
set -xe # x表示是打印每一个运行的命令;e表示有任何错误就退出
echo "Running Post Receive Hook"
export GIT_WORK_TREE=$HOME/my_code
export GIT_DIR=${GIT_WORK_TREE}/.git
cd ${GIT_WORK_TREE}
git fetch origin
git reset --hard origin/master
# reload my apps
# pkill -HUP uwsgi
你可以在文件的尾部加一些应用重置命令(如果你用uwsgi运行python应用的话就可以用如上所示案例)。
将此文件加入git后push到远端服务器
git add post-receive.hook
git commit -m "Add post receive hook"
git push stg master
下一步是在服务器checkout出一份代码
# In remote server
cd ~
git clone my_repo my_code
这个时候就会出现my_repo文件夹,里面会有你的代码。同时,这个代码文件夹的默认origin远端(remote)就会变成my_repo文件夹。当你做git fetch git pull等动作的时候就会从my_repo取信息。
下一步是将挂钩脚本放入repo中
ln -s ~/my_code/post-receive.hook ~/my_repo/hooks/post-receive
注意,这个文件链接一定要放在hooks文件夹内,名字必须叫post-receive
这个时候基本就设置好了
push-to-deploy
下面就可以试验push-to-deploy的效果了。在本地文件夹
touch README.md
git add README.md
git commit
git push stg master
你将会看到一系列的消息
技术细节
你会注意到,post-receive脚本内有这两行
export GIT_WORK_TREE=$HOME/my_code
export GIT_DIR=${GIT_WORK_TREE}/.git
这是告诉git,当你运行的时候所有跟代码本身有关的操作都对my_code进行,所有跟git索引和数据库有关的操作都基于my_code/.git下面。
网上很多现有的方案都是用得checkout -f,他们都不改变GIT_DIR变量。这就导致了my_code/.git并不更新,就像是把my_repo拿过来变成.git然后做一堆checkout操作,然后再恢复原来的.git文件夹,所以所有的新代码都处于unstaged状态。
本文提到的这样做的好处是,你可以利用git push -f进行一些试验性的操作。加入你修改了一个本地文件,你需要部署到staging服务器,那么你就可以用
git add my_changed_file
git commit -m "informal commit"
git push stg master
这个时候你发现不好用又做了一次修改,你可以直接覆盖+暴力推送,而不产生一个新的提交(commit)
git add my_changed_file
git commit --amend --no-edit
git push -f stg master
等到你完全满意了以后,你可以正式推送到官方代码库和production服务器
git commit --amend -m "Real commit"
git push -f stg master
git push origin master # like github.com
git push prod master # if you have this remote
这样的话你的那些修改的中间状态就不会进到官方的代码库,不会被别人看到。
当然,对production服务器和主代码库做暴力推送是不提倡的,在有多人在开发的时候应该是禁止的。
以上。
我的github: github.com/zhongjiewu 如有问题可以留在评论里。
转载:http://zhuanlan.zhihu.com/airbnb/19757507