20.3 StGit和Quilt
一个复杂功能的开发一定是由多个提交来完成的,对于在以接收和应用补丁文件为开发模式的项目中,复杂的功能需要通过多个补丁文件来完成。补丁文件因为要经过审核才能被接受,因此针对一个功能的多个补丁文件一定要保证各个都是精品:补丁1用来完成一个功能点,补丁2用来完成第二个功能点,等等。一定不能出现这样的情况:补丁3用于修正补丁1的错误,补丁10改正了补丁7中的文字错误,等等。这样就带来补丁管理的难题。
实际上基于特性分支的开发又何尝不是如此?在将特性分支归并到开发主线前,要接受团队的评审,特性分支的开发者一定想将特性分支上的提交进行重整,把一些提交合并或拆分。使用变基命令可以实现提交的重整,但是操作起来会比较困难,有什么好办法呢?
20.3.1 StGit
StGit[1]是Stacked Git的简称。StGit就是解决上面提到的两个难题的答案。实际上StGit在设计上参考了一个著名的补丁管理工具Quilt,并且可以输出Quilt兼容的补丁列表。在本节的后半部分会介绍Quilt。
StGit是一个Python项目,安装起来还是很方便的。在Debian/Ubuntu下,可以直接通过包管理器安装:
$sudo aptitude install stgit stgit-contrib
下面还是用hello-world版本库,进行StGit的实践。
(1)首先检出hello-world版本库。
$cd/path/to/my/workspace/
$git clone file:///path/to/repos/hello-world.git stgit-demo
$cd stgit-demo
(2)在当前工作区初始化StGit。
$stg init
(3)现在补丁列表为空。
$stg series
(4)将最新的三个提交转换为StGit补丁。
$stg uncommit-n 3
Uncommitting 3 patches…
Now at patch "translate-for-chinese"
done
(5)现在补丁列表中有三个文件了。
第一列是补丁的状态符号。加号(+)代表该补丁已经应用在版本库中,大于号(>)用于标识当前的补丁。
$stg ser
+fix-typo-help-to-help
+add-i18n-support
>translate-for-chinese
(6)现在查看master分支的日志,发现和之前没有两样。
$git log-3—oneline
c4acab2 Translate for Chinese.
683448a Add I18N support.
d81896e Fix typo:-help to—help.
(7)执行StGit补丁出栈的命令,会将补丁撤出应用。使用-a参数会将所有补丁撤出应用。
$stg pop
Popped translate-for-chinese
Now at patch "add-i18n-support"
$stg pop-a
Popped add-i18n-support—fix-typo-help-to-help
No patch applied
(8)再来看看版本库的日志,会发现最新的三个提交都不见了。
$git log-3—oneline
10765a7 Bugfix:allow spaces in username.
0881ca3 Refactor:use getopt_long for arguments parsing.
ebcf6d6 blank commit for GnuPG-signed tag test.
(9)查看补丁列表的状态,会看到每个补丁前都用减号(-)标识。
$stg ser
-fix-typo-help-to-help
-add-i18n-support
-translate-for-chinese
(10)执行补丁入栈,即应用补丁,使用命令stg push或stg goto,注意stg push命令和git push命令风马牛不相及。
$stg push
Pushing patch "fix-typo-help-to-help"…done(unmodified)
Now at patch "fix-typo-help-to-help"
$stg goto add-i18n-support
Pushing patch "add-i18n-support"…done(unmodified)
Now at patch "add-i18n-support"
(11)现在处于应用add-i18n-support补丁的状态。这个补丁有些问题,本地化语言模板有错误,我们来修改一下。
$cd src/
$rm locale/helloworld.pot
$make po
xgettext-s-k_-o locale/helloworld.pot main.c
msgmerge locale/zh_CN/LC_MESSAGES/helloworld.po locale/helloworld.pot-o locale/temp.po
.完成。
mv locale/temp.po locale/zh_CN/LC_MESSAGES/helloworld.po
(12)现在查看工作区,发现工作区有改动。
$git status-s
M locale/helloworld.pot
M locale/zh_CN/LC_MESSAGES/helloworld.po
(13)不要提交,而是执行stg refresh命令更新补丁。
$stg refresh
Now at patch "add-i18n-support"
(14)这时再查看工作区,发现本地修改不见了。
$git status-s
(15)执行stg show会看到当前的补丁add-i18n-support已经更新。
$stg show
…
(16)将最后一个补丁应用到版本库,遇到冲突。这是因为最后一个补丁是对中文本地化文件的翻译,因为翻译前的模板文件被更改了所以造成了冲突。
$stg push
Pushing patch "translate-for-chinese"…done(conflict)
Error:1 merge conflict(s)
CONFLICT(content):Merge conflict in
src/locale/zh_CN/LC_MESSAGES/helloworld.po
Now at patch "translate-for-chinese"
(17)这个冲突文件很好解决,直接编辑冲突文件helloworld.po即可。编辑好之后,注意一下第50行和第62行是否像下面写的一样。
50 "hello-h,—help\n"
51 "显示本帮助页。\n"
…
61 msgid "Hi,"
62 msgstr "您好,"
(18)执行git add命令完成冲突解决。
$git add locale/zh_CN/LC_MESSAGES/helloworld.po
(19)不要提交,而是使用stg refresh命令更新补丁,同时更新提交。
$stg refresh
Now at patch "translate-for-chinese"
$git status-s
(20)看看修改后的程序,是不是都能显示中文了。
$./hello
世界你好。
(version:v1.0-5-g733c6ea)
$./hello Jiang Xin
您好,Jiang Xin.
(version:v1.0-5-g733c6ea)
$./hello-h
…
(21)导出补丁,使用命令stg export。导出的是Quilt格式的补丁集。
$cd/path/to/my/workspace/stgit-demo/
$stg export-d patches
Checking for changes in the working directory…done
(22)看看导出补丁的目标目录。
$ls patches/
add-i18n-support fix-typo-help-to-help series translate-for-chinese
(23)其中文件series是补丁文件的列表,列在前面的补丁先被应用。
$cat patches/series
This series applies on GIT commit d81896e60673771ef1873b27a33f52df75f70515
fix-typo-help-to-help
add-i18n-support
translate-for-chinese
通过上面的演示可以看出StGit可以非常方便地对提交进行整理,整理提交时无须使用复杂的变基命令,而是采用提交StGit化、修改文件、执行stg refresh的工作流程即可更新补丁和提交。StGit还可以将补丁导出为补丁文件,虽然导出的补丁文件没有像git format-patch那样加上代表顺序的数字前缀,但是用文件series标注了补丁文件的先后顺序。实际上可以在执行stg export时添加-n参数为补丁文件添加数字前缀。
StGit还有一些功能,如合并补丁/提交,插入新补丁/提交等,请参照StGit帮助,恕不一一举例。