自动化是提高开发效率的有效手段之一。在源码管理过程中要实现自动化,必须能够知道源码管理工具内部的事件进行状态,显然对于这些独立工具是没办法像在同一个程序中一样进行类似 KVO 式的外部监听,好在 Git 就像一个设计完备的库一样提供了部分关键流程的调用接口,也就是 githooks。

将要处理的情景是在使用 Git 做版本管理,用 Cocoapods 进行第三方库管理的项目中

  1. 从服务器 pull 下来后 Podfile.lock 发生变化,也就是本地 pod 和服务器中的不一致,需要 pod install
  2. 从服务器 pull 下来证书发生变化,在一个开发团队里每个人有自己的证书用于真机调试,需要改为自己的证书
  3. 切换分支后 Podfile.lock 发生变化,需要 pod install

githooks 本身是一个个有固定名称的脚步,相当于有固定名称的 delegate 方法,在每一次执行所绑定 git 命令时触发,例如 pre-commitpost-commit 分别会在 git commit 的前后触发,githooks 可以是任意系统支持运行的脚本如 Shell Perl Python Ruby。

githooks 支持绑定的类型都列在了文档里 man githooks。为了实现场景1、2的自动化需要使用的是 post-mergepost-merge 绑定的命令是 `git merge 和 git pull,post 前缀类型的 githook 不能影响 git 命令本身的执行,pre 前缀的 hook 可以。新版本的 git 项目在初始化的时候在根目录都建有 .git/hooks/ 目录,里面存放所有 hook ,打开这个文件夹里面默认有一些sample后缀的示例文件,去掉 .sample 这些示例才能真正运行,如果已经有 post-merge 去掉 sample 后缀,如果没有新建 post-merge 文件添加可执行权限 chmod +x post-merge,添加脚本内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env ruby
#1
require 'xcodeproj'
#2
cmd = ' changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
echo "$changed_files" | grep --quiet "Podfile.lock" && eval "pod install"
echo "pod installed" '
system( cmd )
#3
xcproj = Xcodeproj::Project.open("DroppingBall.xcodeproj")
xcproj.build_configurations.each do |item|
item.build_settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = "iOS Development: Weizhou Feng (XXXXXXXXXX)"
item.build_settings['PROVISIONING_PROFILE[sdk=iphoneos*]'] = “xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
end
#4
xcproj.save

第一行声明这是一个 Ruby 脚本,使用 Ruby 的原因是可以直接用 xcodeproj 这个库, cocoapods 使用这个库创建或修改xcode 的项目文件,这里需要用它修改 project.pbxproj 内容

#1 引入 xcodeproj 库

#2 pull 之后获取 git 状态还是 shell 命令方便不需要增加依赖,所以直接在脚本中调用 shell 命名可以分为三步:

  1. git diff 取得 pull 之后发生变化的所有文件名称
  2. grep 判断是否包含 Podfile.lock
  3. 如果有执行 pod install
    更新结束后在终端输出 pod installed

#3 打开当前项目文件,DroppingBall 是这里的项目名称。读取构建模式一般有两种:Debug 和 Release,分别将其中的 build setting 选项 CODE_SIGN_IDENTITY 和 PROVISIONING_PROFILE 改为自己的,要赋的值可以现在 Xcode 中通过菜单选择正确的选项然后打开 project.pbxproj 把文本内容复制出来用

#4 保存

然后是情景3,切换分支需要的 hook 是 post-checkout,和上面一样保证 post-checkout 在文件夹里存在,添加内容:

1
2
3
4
5
#!/bin/sh
if ! diff -q "Podfile.lock" "Pods/Manifest.lock" > /dev/null ; then
pod install
fi

这次是 shell 脚本,所做的事情其实和 cocoapods 做的一样,只不过 cocoapods 的脚本会在 xcode 里生成一个 error: The sandbox is not in sync with the Podfile.lock. Run ‘pod install’ or update your CocoaPods installation. 这里则是直接执行 pod install

资源:
http://githooks.com