Mercurial 合并提交

2009 年 7 月 9 日

我最近用 Mercurial 合并了一些提交,所以想写一篇博文,以防其他人也想要这样做。我不知道这是否是最好的方法,但对我来说似乎效果很好。

hg clone base working
# tip of base is revision 73
cd working
# do work, committing on the way
cd ..
hg clone working squash
cd squash
hg qimport -r 74:tip
hg qgoto 74.diff
hg qfold $(hg qunapp)
hg qfinish -a
cd ../base
hg pull ../squash

我做的基本任务是将一些文件和文件夹进行相当严重的移动。我想分几个步骤来完成这项工作,以便在过程中对我的工作进行检查点,但我想要在版本历史中进行一次提交。(我了解到 git 可以通过 rebase 更轻松地做到这一点。)进行一次提交可以更容易地理解发生了什么 - 特别是由于移动文件往往会使查看存储库日志变得复杂。移动文件也会使流程变得复杂 - 有几次我最终得到一个无法正常工作的流程,因为它失去了跟踪移动的能力 - 我希望能够执行 hg log -f 并查看在移动之前原始提交的时间和内容。

首先,我需要启用 mq 扩展(Mercurial 队列)并将我的差异设置为 git 风格。Git 风格的差异有助于正确跟踪文件移动。

# in ~/.hgrc
[extensions]
mq=

[diff]
git=true 

以这种方式使用 Mercurial 时,似乎一般的工作方式是拥有多个存储库。Mercurial 鼓励使用不同的存储库,而其他系统(例如 git 或 svn)会使用不同的分支。人们对此争论不休,但这是 Mercurial 的工作方式。在这个例子中,我将“base”作为我的原始存储库。

我的第一步是将 base 克隆到一个工作存储库中。

hg clone base working

此时,base(和 working)的顶端是修订版 73。我进行了文件移动,并在过程中进行了几个检查点修订。

cd working
hg mv foo1 newdir/foo1
.. more hg mv ..
hg ci -m "moving around"
.. more hg mv ..
hg ci -m "moving around"
.. more hg mv and hg ci..
cd ..

当我完成时,最后一个修订版是 80。

为了将它们压缩成一个提交,我克隆了另一个存储库。

hg clone working squash

此时克隆很重要,因为我将要编辑历史记录,所以我想保留原始历史记录,直到我知道它已经成功。我现在进入那里。

cd squash

现在,我将为修订版完成的所有提交都变成了 Mercurial 修补程序队列机制的修补程序。

hg qimport -r 74:tip

我将第一个更改设置为当前修补程序

hg qgoto 74.diff

我将所有修补程序压缩成一个修补程序

hg qfold $(hg qunapp)

这个折叠修补程序的提交消息将是所有单独的提交消息链接在一起。我想要一个单独的消息来表示我的干净提交。

hg qrefresh -m "reorganized files"

然后,我将修补程序变成了一个常规的提交。

hg qfinish -a

我现在有一个包含所有工作的单个提交。我查看了它,以确保一切正常,特别是测试了 hg log -f 对一些移动的文件,以确保历史记录仍然存在。一旦我确信一切正常,我就将单个变更集拉入 base 存储库。

 
cd ../base
hg pull ../squash
  

有趣的是,看看多年来人们对版本控制系统的关注是如何变化的。早期,主要且唯一的目的是审计 - 能够安全地回到旧的修订版 - 主要用于诊断问题。然后,人们的注意力转移到它们如何使人们之间的协作成为可能。这并没有取代对审计的需求,而是在其基础上进行了构建。现在,人们更加关注使用它们来提供代码库如何变化的叙述 - 因此人们渴望使用像这样的历史重写命令。同样,这种需求是在其他两种需求的基础上构建的,但它引入了新的功能和新的紧张局势。

感谢我的同事 Chris Turner 的帮助,我还发现 这个页面 非常有用。