使用 Git Hooks 实现自动项目部署

最近在某服务器上面搭建 git 开发和部署环境,git 开发环境很简单,按照 ProGit 一书的相关知识就可以轻松搞定,实现了类似 Github 的使用 SSH + 私有 Clone 的方式。

关于部署,奇迹上是自动部署,起初的想法是使用 bash shell 制定一个定时任务去不断 git pull 产品代码,后来记得 Git 带有 Hooks,索性在 ProGit 一书翻了翻:

Git 本身可以调用自定义的挂钩脚本,其中有两组:客户端和服务器端。客户端挂钩用于客户端的操作,如提交和合并。服务器端挂钩用于 Git 服务器端的操作,如接收被推送的提交。详情请查看 ProGit 相关章节

如果这样就简单了,利用服务器端调用想要的挂钩(Hook),即可实现自动部署的方案,为了保证不被肆意部署,特加了一个对需要部署 commit 的判断,利用读取 commit subject 并匹配想要的字符串才去部署,这样我认为是一个比较安装的部署方案。

Git的挂钩(Hook)主要包含:

  • applypatch-msg
  • post-update
  • pre-rebase
  • commit-msg
  • pre-applypatch
  • update
  • post-commit
  • pre-commit
  • post-receive
  • prepare-commit-msg

这里我们只需要使用 post-receive 这个 Hook:在接收 post(push) 请求之后执行。其他大部分我也没有大多研究,不过看名字不算难理解,我觉得其中大部分包含 commit 的属于客户端。

好了,部署开始:

1. 在服务器 git 仓库(注意是 bare 仓库,不是代码仓库)的 Hooks,编辑 post-receive(如果没有自行创建),贴入下面代码(Feed 用户请看这里):

这里会先判断脚本所在目录是否是 bare git 仓库,然后获取最新 commit 的 subject,并匹配是否包含 [deploy] 字样,如果包含,则继续检查产品代码仓库路径是否存在,如果存在则执行 git pull 操作。

2. 对刚才编辑的 post-receive 执行下面命令以保证脚本可执行:

$ chmod +x post-receive

3. 完成!

————————————-

对于自定义脚本,其实不仅限于 bash shell,你可以使用你熟悉的语言,然后把你的脚本路径在 hooks 脚本中加载即可。

脚本还会继续更新,下面需要增加关于测试部分的相关判断和部署。 bash shell 还需要进一步学习,上面脚本是我第一次写,如有不妥之处,请指教,感谢!

如何保持在 Git Submodule 代码的开放和私有共存

假设我在 github 有一个开源的版本库 x 供大家使用,该库里面又包含了好些个 submodules,其中有一个 submodule 名为 a 是自己在 github 又创建的:

$ git submodule add  http://github.com/icyleaf/a.git modules/a

现在问题是,由于代码需要更新,同时涉及到了 a 这个 submodule,但是它的添加 url 是 read-only,由于 x 这个库是供大家使用,因此 a 又不能设为 private:

$ git clone git@github.com:icyleaf/a.git modules/a

目前想到的方法是在 x 库以外 clone 下来 a,进行私有的写入和 push 到 github 上面,然后在 x 库的 a 里 git pull 下来获得最新的代码。

如何解决这样的问题,能够当大家全部 clone 下来,而自己开发也能避免麻烦?

在一篇文章上面找到了灵感,折腾了一番搞定了

该文章有一节讲到,开发者如果经常需要更新 submodule ,即可更换 submodule 的 remote url:

$ cd commonlib
$ git remote rm origin
$ git remote add origin ssh://mark@git.mysociety.org/data/git/public/commonlib.git
$ git remote -v
origin    ssh://mark@git.mysociety.org/data/git/public/commonlib.git

However, you’ll find that two helpful config options will have been deleted when removing and adding back origin, so you’ll want to add these back.

$ git config branch.master.remote origin
$ git config branch.master.merge refs/heads/master

首先我也先对 a 进行 git remote -v,结果显示:

origin	http://github.com/icyleaf/a.git (fetch)
origin	http://github.com/icyleaf/a.git (push)

发现和文章里面的显示的结果不一样,于是我就在想能不能在 remote 上面做些手脚,首先看下 git remote 的 help,发现有一条是可以单独设置 remote push 的 url ,也就是更换上面 git remote -v 中 push 的 url,尝试:

$ git remote set-url --push origin git@github.com:icyleaf/a.git

再次执行 remote -v:

origin	http://github.com/icyleaf/a.git (fetch)
origin	git@github.com:icyleaf/a.git (push)

执行成功!然后随意 commit 并 push orgin master,成功!

搞定!

几本和 Git 相关的书

切换到 Git开发已经有一段的时间了,之前一直在使用 svn,现在部分代码还在 Google Code 托管。不过自换了 Git 之后发现 Git 更方便且效率更高,不过用来用去常用的就拿几个命令,很多时候都要去找一些参考资料和教程。从学习到现在一个接触了一个文档,三本书。文档就是官方的文档手册,这个就不再说了,安装完 git 也都会默认内置的,对于这三本书,依次为 Git Community BookProGitWhy Git is Better Than X(X 代表其他 SCM 软件,如 svn,bzr等)。

  • Why Git is Better Than X 已经有国内友人翻译完毕,一一介绍了 Git 与其他 SCM 软件有什么优势和特色
  • ProGit 不久前开启了翻译计划,中文目前还在翻译过程中, 这本书很适合作为入门使用和工具书,欢迎前来 Fork
  • Git Community Book 就是一个由社区维护的手册,内容很全讲解的很详细,就是还没有中文

可喜的是,这些书籍都是可以在线观看或下载的,当然如果能进一份力量,请去购买正版,或有一腔热血为 Git 贡献,就请加入到翻译之中。

初学 git 入门

Git 是用于 Linux 内核开发的版本控制工具。与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。 Git 的速度很快,这对于诸如 Linux kernel 这样的大项目来说自然很重要。 Git 最为出色的是它的合并跟踪(merge tracing)能力。

当前大多数人用的还应该是 SVN 服务,不过上次见到 CNBorn 同学使用 git 做版本控制,其实知道它很早不过没有过多的了解,在我稍微了解之后发现 git 比 svn 更具潜力,可惜对于 PHP 的用户来说还没有多少人开始用 git 甚至我在 PHPChina 的论坛看到有人问 git 的问题,居然有人回答 git 是什么…

同样 git 支持多平台且对于 Windows 的用户也有 GUI 的管理界面。通过几天的了解是使用稍微掌握了一点入门的东西(以下都是命令行的东西,如果你想学习使用 GUI 的操作请看此讲解视频);
首先是下载并安装 git。接着设置用户标识:

git config --global user.name yourname
git config --global user.email example@mail.com

然后创建一个目录作为版本库:

mkdir example
cd example
git init

把本地文件同步到远程 git host 服务网站上面

# 添加文件
git add filename
# 提交说明并提交
git commit -m 'first commit'
# 添加到远程地址,这个地址不固定,以 git hosts 提供地址为准
git remote add origin git@example.com:username/example.git
# 提交 origin 到 master
git push origin master

另外,如果使用网上的 git host 服务,还涉及到设置 ssh public key 的问题,各个平台有些细微的差别,大家看 github 网站的相关帮助

如果你想系统的学习 git, 不妨通读下 《看日记学git》系列文章