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帮助,恕不一一举例。

    [1]http://www.procode.org/stgit/