2010-10-25

脱离 Gerrit 审核服务器,使用 repo

Gerrit 代码审核服务器部署比较麻烦,更不要说因为 Gerrit 界面的学习和用户使用习惯的更改而带来的困难了。而且在一个固定的团队内部使用 repo 可能真的没有必要使用 Gerrit,因为团队成员都应该熟悉 Git 的操作,团队成员的编程能力都可信,单元测试质量由提交者保证,集成测试由单独的测试团队进行,即团队拥有一套完整、成型的研发工作流,Gerrit 并不适合引入。 脱离了 Gerrit 服务器,直接跟 Git 服务器打交道,repo 可以工作么?... 为了筹备中的 gitbook,我特意为 repo 增加了 repo push 的实现,效果和预期的一样好。

5.6.9.3   改进的 Repo 无审核模式

前面介绍的使用 repo forall 迭代器实现无审核服务器模式下向上游提交代码,只是权宜之计,尤其是用 repo start 建立工作分支要求和上游一致,实在是有点强人所难。 我改造了 repo,增加了两个新的子命令 repo config 和 repo push ,让 repo 可以脱离 Gerrit 服务器直接向上游提交。代码托管在 Github 上: http://github.com/ossxp-com/repo 。下面简单介绍一下如何使用改造之后的 repo。
5.6.9.3.1   下载改造后的 repo 引导脚本
建议使用改造后的 repo 引导脚本替换原脚本,否则在执行 repo init 命令需要提供额外的 --no-repo-verify 参数,以及 --repo-url 和 --repo-branch 参数。
$ curl http://github.com/ossxp-com/repo/raw/master/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
5.6.9.3.2   用 repo 从 Github 上检出测试项目
如果安装了改造后的 repo 引导脚本,使用下面的命令初始化 repo 及清单库。
$ mkdir test
$ cd test
$ repo init -u git://github.com/ossxp-com/manifest.git
$ repo sync
如果用的是老的 repo 脚本,用下面的命令。
$ mkdir test
$ cd test
$ repo init --repo-url=git://github.com/ossxp-com/repo.git \
  --repo-branch=master --no-repo-verify \
  -u git://github.com/ossxp-com/manifest.git
$ repo sync
当子项目代码全部同步完成后,执行 make 命令。可以看到各个子项目的版本以及清单库的版本。
$ make
Version of test1:    1:0.2-dev
Version of test2:    2:0.2
Version of manifest: current
5.6.9.3.3   用 repo config 命令设置 pushurl
现在如果进入到各个子项目目录,是无法成功执行 git push 命令的,因为上游 Git 库的地址是一个只读访问的 URL,无法提供写服务。我们可以用新增的 repo config 命令设置当执行 git push 时的 URL 地址。
$ repo config repo.pushurl ssh://git@github.com/ossxp-com/
设置成功后,可以使用 repo config repo.pushurl 查看设置。
$ repo config repo.pushurl
ssh://git@github.com/ossxp-com/
5.6.9.3.4   创建本地工作分支
使用下面的命令创建一个工作分支 jiangxin 。
$ repo start jiangxin --all
使用 repo branches 命令可以查看当前所有的子项目都属于 jiangxin 分支
$ repo branches
*  jiangxin                  | in all projects
参照下面的方法修改 test/test1 子项目。对 test/test2 项目也作类似修改。
$ cd test/test1
$ echo "1:0.2-jiangxin" > version
$ git diff
diff --git a/version b/version
index 37c65f8..a58ac04 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1:0.2-dev
+1:0.2-jiangxin
$ repo status
# on branch jiangxin
project test/test1/                             branch jiangxin
 -m     version
$ git add -u
$ git commit -m "0.2-dev -> 0.2-jiangxin"
执行 make 命令,看看各个项目的改变。
$ make
Version of test1:    1:0.2-jiangxin
Version of test2:    2:0.2-jiangxin
Version of manifest: current
5.6.9.3.5   PUSH 到远程服务器
直接执行 repo push 就可以将各个项目的改动进行提交。
$ repo push
如果有多个项目同时进行了改动,为了避免出错,会弹出编辑器显示有改动需要提交的项目列表。
# Uncomment the branches to upload:
#
# project test/test1/:
#  branch jiangxin ( 1 commit, Mon Oct 25 18:04:51 2010 +0800):
#         4f941239 0.2-dev -> 0.2-jiangxin
#
# project test/test2/:
#  branch jiangxin ( 1 commit, Mon Oct 25 18:06:51 2010 +0800):
#         86683ece 0.2-dev -> 0.2-jiangxin
每一行前面的井号是注释,被忽略的行。将希望提交的分支前的注释去掉,就可以将该项目的分支执行推送动作。如下我们把两个分支的注释都去掉了,要对这两个项目当前分支的改动 push 到上游服务器。
# Uncomment the branches to upload:
#
# project test/test1/:
branch jiangxin ( 1 commit, Mon Oct 25 18:04:51 2010 +0800):
#         4f941239 0.2-dev -> 0.2-jiangxin
#
# project test/test2/:
branch jiangxin ( 1 commit, Mon Oct 25 18:06:51 2010 +0800):
#         86683ece 0.2-dev -> 0.2-jiangxin
保存退出(如果使用 vi 编辑器,输入 :wq 执行保存退出)后,马上开始对选择的各个项目执行 git push。
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 293 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git@github.com/ossxp-com/test1.git
   27aee23..4f94123  jiangxin -> master
Counting objects: 5, done.
Writing objects: 100% (3/3), 261 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git@github.com/ossxp-com/test2.git
   7f0841d..86683ec  jiangxin -> master

--------------------------------------------
[OK    ] test/test1/     jiangxin
[OK    ] test/test2/     jiangxin
从提交日志我们可以看出来本地的工作分支 jiangxin 的改动被推送的远程服务器的 master 分支(本地工作分支跟踪的上游分支)。 我们再次执行 repo push ,会显示没有项目需要提交。
$ repo push
no branches ready for upload
5.6.9.3.6   在远程服务器创建新分支
如果我们想在服务器双创建一个新的分支,该如何操作呢?
$ repo start feature1 --all
$ repo push --new_branch
经过同样的编辑器选择之后,自动调用 git push ,在服务器上创建新分支 feature1 。
Total 0 (delta 0), reused 0 (delta 0)
To ssh://git@github.com/ossxp-com/test1.git
 * [new branch]      feature1 -> feature1
Total 0 (delta 0), reused 0 (delta 0)
To ssh://git@github.com/ossxp-com/test2.git
 * [new branch]      feature1 -> feature1

--------------------------------------------
[OK    ] test/test1/     feature1
[OK    ] test/test2/     feature1
我们也可以用 git ls-remote 命令查看远程服务器上的分支。
$ git ls-remote git://github.com/ossxp-com/test1.git refs/heads/*
4f9412399bf8093e880068477203351829a6b1fb        refs/heads/feature1
4f9412399bf8093e880068477203351829a6b1fb        refs/heads/master
b2b246b99ca504f141299ecdbadb23faf6918973        refs/heads/test-0.1
我们注意到 feature1 和 master 分支引用指向相同的 SHA1 哈希值,这是因为我们直接从 master 分支创建的 feature1 分支。
5.6.9.3.7   通过不同的清单库版本,切换到不同分支
换用不同的清单库,需要建立新的工作区,并且在执行 repo init 时,通过 -b 参数指定清单库的分支。
$ mkdir test-0.1
$ cd test-0.1
$ repo init -u git://github.com/ossxp-com/manifest.git -b test-0.1
$ repo sync
当子项目代码全部同步完成后,执行 make 命令。可以看到各个子项目的版本以及清单库的版本不同于之前的输出。
$ make
Version of test1:    1:0.1.4
Version of test2:    2:0.1.3-dev
Version of manifest: current-2-g12f9080
我们可以用 repo manifest 命令来查看清单库。
$ repo manifest -o -
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote fetch="git://github.com/ossxp-com/" name="github"/>

  <default remote="github" revision="refs/heads/test-0.1"/>

  <project name="test1" path="test/test1">
    <copyfile dest="Makefile" src="root.mk"/>
  </project>
  <project name="test2" path="test/test2"/>
</manifest>
仔细看上面的清单文件,可以注意到缺省的版本指向到 refs/heads/test-0.1 引用所指向的分支 test-0.1 。 如果我们在子项目中修改、提交,然后使用 repo push 会将改动推送的远程版本库的 test-0.1 分支中。
5.6.9.3.8   切换到清单库里程碑版本
执行如下命令,我们可以查看清单库包含的里程碑版本:
$ git ls-remote --tags git://github.com/ossxp-com/manifest.git
43e5783a58b46e97270785aa967f09046734c6ab        refs/tags/current
3a6a6da36840e716a14d52252e7b40e6ba6cbdea        refs/tags/current^{}
4735d32613eb50a6c3472cc8087ebf79cc46e0c0        refs/tags/v0.1
fb1a1b7302a893092ce8b356e83170eee5863f43        refs/tags/v0.1^{}
b23884d9964660c8dd34b343151aaf968a744400        refs/tags/v0.1.1
9c4c287069e29d21502472acac34f28896d7b5cc        refs/tags/v0.1.1^{}
127d9789cd4312ed279a7fa683c43eec73d2b28b        refs/tags/v0.1.2
47aaa83866f6d910a118a9a19c2ac3a2a5819b3e        refs/tags/v0.1.2^{}
af3abb7ed0a9ef7063e9d814510c527287c92ef6        refs/tags/v0.1.3
99c69bcfd7e2e7737cc62a7d95f39c6b9ffaf31a        refs/tags/v0.1.3^{}
我们可以从任意里程碑版本的清单库初始化整个项目。
$ mkdir v0.1.2
$ cd v0.1.2
$ repo init -u git://github.com/ossxp-com/manifest.git -b refs/tags/v0.1.2
$ repo sync
当子项目代码全部同步完成后,执行 make 命令。可以看到各个子项目的版本以及清单库的版本不同于之前的输出。
$ make
Version of test1:    1:0.1.2
Version of test2:    2:0.1.2
Version of manifest: v0.1.2
blog comments powered by Disqus