読者です 読者をやめる 読者になる 読者になる

MQの適用済みパッチをrebaseする #mercurialjp

このエントリはMercurial Advent Calendar 2013 の16日目です。

MQを使っていて困るのが、ファイル名の変更です。

  1. あるファイルAに対してパッチaを作成していて
  2. 最新版を取り込んだらファイルAはファイルBに変更されていて
  3. 最新のソースにパッチaが簡単に適用できない

的な。こんなときはhg rebaseを使いましょう。

下準備

確認用のリポジトリを作成します

$ hg init mq+rebase
$ cd mq+rebase

ファイルを追加してコミット&編集してコミットします。

$ vi README
$ cat README
README
======

りーどみーです
$ hg add README
$ hg ci -m "add README"
$ hg mv README README.md
$ hg ci -m "rename README.md"

変更前に移動して、ファイルを変更してMQのパッチを作ります。

$ hg up 0
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ vi README 
$ hg qnew fix-readme.diff
$ hg qdiff
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
 README
 ======

-りーどみーです
+READMEです

ここまでで、次のようなグラフになっています。

$ hg log -G --style compact
@  2[fix-readme.diff,qbase,qtip,tip]:0   6dd9b66a5c49   2013-12-14 18:09 +0900   trot
|    [mq]: fix-readme.diff
|
| o  1   fd9f6575c27b   2013-12-14 18:09 +0900   trot
|/     rename README.md
|
o  0[qparent]   a7b49ee46b61   2013-12-14 18:09 +0900   trot
     add README

MQに対してhg rebaseを行う

では適用済みのパッチであるrevision 2revision 1にrebaseしてみます。

$ hg rebase --source 2 --dest 1 --keep
merging README.md and README to README.md
patch fix-readme.diff finalized without changeset message

変更内容とグラフはこんな感じ。

% hg qdiff
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
 README
 ======

-りーどみーです
+READMEです
% hg log -G --style compact
@  3[fix-readme.diff,qbase,qtip,tip]:1   4cc4f45e60a3   2013-12-14 18:09 +0900   trot
|    [mq]: fix-readme.diff
|
| o  2:0   6dd9b66a5c49   2013-12-14 18:09 +0900   trot
| |    [mq]: fix-readme.diff
| |
o |  1[qparent]   fd9f6575c27b   2013-12-14 18:09 +0900   trot
|/     rename README.md
|
o  0   a7b49ee46b61   2013-12-14 18:09 +0900   trot
     add README

やりましたね!

パッチかリビジョンか

hg rebaseの対象にする適用済みパッチの範囲によってちょっと挙動が異なるので、説明しておきます。

  1. 対象が適用済みパッチすべての場合

    • hg rebase後の新しい変更はパッチになる
    • (--keepした場合)元の変更はリビジョンになる
  2. 対象が適用済みパッチの一部の場合

    • hg rebaseは失敗するので
    • hg rebase --abortで復旧する(このときゴミリビジョンが残る)

リビジョンの指定を誤り2のケースを行ってもパッチは壊れません。安心して使えますね。

追記:MQをバージョン管理している場合。

今回の例の様にhg rebaseはパッチの内容を変更する操作でもあります。MQをバージョン管理している場合、hg rebase実行後はhg st --mqhg ci --mqを忘れないようにしてください。

まとめ

  • MQの適用済みパッチに対してhg rebaseが行える。
  • hg rebaseするときは適用済みパッチすべてを対象にするよう気をつける。