HG的秘密武器 — Mercurial Queue

Why

惯用版本管理的coder会发现,经常整理代码时候,要提交出一个完美的版本库还真不容易,有时候不仔细连语法错误的版本都commit进去了仓库,如果以洁癖的眼光看,这是不可容忍的:

  • 仓库每个版本均可无错编译
  • 每次提交的目的简单明了,不应多个不相关修改合在同一次commit
  • 提交说明可以简单明了和修改了的代码联系起来

Mercurial 默认配置情况下不易做到这个,相比起git,hg没有git的index概念,一次commit可以经过多次记录才确认成一个版本。但是hg自带了个插件Mercurial Queue,功能上可比git更胜一筹。

考虑这么一个情况,在做新功能探索的代码,尝试到有一步成果了,但后面出现几种方案需要测试,暂时还不知道用那个。如果把目前的版本提交,又不成熟,不足以作为一个版本。有mq的话,直接qrefresh记录当前的修改,再随便折腾代码,不爽直接revert,这个记录还没有成为commit,直到最后觉得满意了,qfinish my_perfect_patch,才最后提交成一个版本。

另外一个情况,在开发新功能时候,代码改了一堆了,突然rp爆发,一眼就发现了以前版本留下的一个很隐藏的bug。

没有mq的话,你有3种方式处理:

  • 记住!好大的BUG!完成这次功能,提交后再Fix掉! (然后忘了)
  • 把这行代码的位置写到paster贴显示器上;
  • 马上修正bug,继续写代码,最后提交版本的时候写: added xxxxxxx; fixed xxxxxx;

都不怎么靠谱吧,使用mq的话,这可不是什么问题:

  1. 暂停coding,记录下目前的进展,qrefreshqpop出当前已有修改。
  2. 创建一个新的patch,qnew fix_xxx
  3. fix bug,qrefreshqfinish fix_xxx。这时仓库里面已经有一个修好bug的版本了。
  4. qpush回到刚才的状态,继续coding新功能。

“提交 commit”是版本管理里面一系列不可修改的历史,一旦提交后就不能修改他们的状态和顺序。mq里面的queue虽然也是历史的部分,但还没有永久成型,可以任意改变,直到成熟,可有效提高仓库中的版本质量。

不过使用mq后这个情况也有点改变,配置好mq后会有了一个邪恶的strip命令,可以从提交历史当中直接删除一个commit。虽然这显然是不尊重历史的,不过作为灵活特性,git也有这样的功能,毕竟特殊时候可以避免信息泄漏等事情。

How

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#几乎所有资料都叫你先运行hg qinit,不过这是过时的命令,所有mq的命令都会默认创建好patch环境
 
# 往常地,在版本目录里面改代码,coding ...
 
# 好了差不多了,我要记录下我刚才这一次优秀的改进,可能还不够完美,但绝对是空前绝后的。
 
hg qnew -m "fabulous improvement" wonderful-2011 # 创建了名为`wonderful-2011` 的一个patch,包括了刚才的所有改动;
 
# 现在hg diff是没有改变输出的;hg qdiff倒有。
 
# 继续浏览了一次刚才的美妙代码,哎呀有好几处暇疵什么的,啊有几个只有半边括号的,好吧已经改善了,已经运行过,跑的很好
 
hg qrefresh  # 现在改善后的代码也记录完成了。
 
# 哎呀发现了个大bug,这个bug应该在之前的代码上就完成修改的
 
hg qpop #把刚才的修改暂时去掉
 
hg qnew -m "fix bug" fix-bug # 新建一个patch
 
# fix bug fix bug fix bug
 
hg qrefresh #记录fix bug的修改
 
hg qfinish fix-bug #把fix-bug提交进去
 
hg qpush # 回到刚才的,wonderful-2011
 
# 继续coding
 
hg qfinish -a # 完美了,把所有patch都commit到仓库。收工。

Advanced

Mercurial Queue 名字虽然叫queue,但里面主要都是一个个patch栈的形式,对每一次patch进行pop/push那样的操作,每个栈称为一个queue,使用qqueue命令可以创建多个queue,并在它们之间自由切换,各个queue内的patch相互独立,自由度非常高(比git还灵活)。

每个队列里面的一系列patch是按先后顺序排列的,要应用的话必须按顺序。但是qguard命令可以让你选择性地应用相应的guard下某些补丁来测试 (orz) 。

其实mq的工作是基于项目目录下.hg/patches里面的内容,里面记录着你所有的patch。细细一想,其实每次qrefresh就是覆盖掉之前的修改,如果不小心改错了怎么办啊!!! 不怕,还有管理版本管理目录的版本管理 (误!),给patches目录建个仓库就是了嘛,mq已经为你设计好了,执行hg init --mq,即可,之后每次qrefresh,都可以qcommit一下让patches里面的仓库记录你的修改。

不过这样的特性太高级了,让我处理那么复杂的补丁机制估计会疯掉的,真有兴趣的同学情参考下列文档。

Reference

初级资料

高级资料

重点推荐A Git User’s Guide to Mercurial Queues,文章比较图文并茂解释mq里面的概念,而且和git特性做了优缺点对比。

文章分类 版本管理 标签: , ,

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*