/!\ このエクステンションの非推奨化を検討していますが、まだ合意がとれていません。

Mercurial Queues エクステンション

現在、このエクステンションは Mercurial とともに配布されています。

作者: Chris Mason

1. MQ を始める方へ一言

Mercurial を始める方が、 MQ を必要とすることはほとんどありません。 あなたが MQ をお使いで、気に入っているのなら、ぜひ使い続けてください。 しかし、 Mercurial を習得しようとしているなら、代わりに最新のツールを使って下さい。 例えば hg rebase, hg histedit, hg graft, hg strip, hg strip --keep, hg commit --amend です。 詳しくは各コマンドの説明をご確認ください。

The problems with MQ is that (1) it introduces a new concept, the patch, which is essentially a commit that doesn't know merge logic and (2) many of its operations (qrefresh, qfold, qdelete) do not produce any backups, so it's easy to lose work.

If you're already an advanced MQ user, for example, you have your patch series under hg control (yo dawg...), and you are feeling adventurous you can try using Evolve right now. It's still a work-in-progress, so beware, but it's already quite usable, and it needs more testers.

2. まえがき

通常、分散開発モデルでは changeset を変更できません。 一度 commit したものは、プロジェクトの履歴に永久に残ることになります。 これでは、プロジェクトメンテナに提出する一連の変更を作るのが面倒でしょう。 コードが成熟するにつれて、開発 repository には長い merges と変更の履歴が蓄積されます。 この履歴は開発者本人にとっては重要ですが、アップストリームに提出された時には非常にレビューしづらいものになるでしょう。

Andrew Morton はかつて、カーネルパッチを SCM の外部で管理するためのスクリプト一式を書きました。 そのスクリプトが拡張され、 quilt というスイートへ発展しました。 quilt の基本的な考えは、ソースファイルの代わりにパッチを管理するということです。 パッチは追加、削除、順序変更可能で、バグを直した場合や新しいバージョンへ追従した場合に更新(refresh)されます。 quilt はとても強力ですが、下層の SCM ツールと統合されていません。 そのため、変更内容を可視化するのは面倒です。

パッチキュー・エクステンションは quilt の機能を Mercurial と統合します。 変更内容は Mercurial にコミットされたパッチとして管理されます。 コミットは削除、順序変更可能で、 下位のパッチは working directory への変更をもとに更新(refresh)されます。 パッチディレクトリもバージョン管理下へ置くことができ、パッチへの変更を別個の履歴として管理することができます。

3. 設定

以下の行を設定ファイル(.hgrc or Mercurial.ini)へ追加し、エクステンションを有効にしてください:

[extensions]
mq =

4. Mercurial Queues の利用

エクステンションを正しくインストールすると、 hg help に mq 系コマンドが追加されているはずです。 コマンド名は q で始まり、 quilt のコマンドをできるだけ真似ています。 パッチキューは .hg/patches というディレクトリにあります。 .hg/patches/series はパッチ適用順のリストです。 series ファイル内の順序を変えるだけで、パッチの順序を変更可能です。 series ファイルを編集する時は、適用中のパッチの項目を変更しないように注意してください。

5. パッチを新しいアップストリーム・バージョンとマージ

Rebase エクステンション を使うと、一連のパッチをアップストリームの最新ヘッドとマージするのがかなり楽になります。たいていの場合、やることはたったのこれだけです:

$ hg pull
$ hg rebase -s <rev1> -d <rev2>

このコマンドは、 rev1 (要は mq に紐付いた最も古い適用済みリビジョン)とその子孫を、 rev2 (pull したばかりの最新ヘッド)へリベースします。必要に応じてマージが行われます。リベースしたいパッチは適用済みでなければなりません。 qpop したパッチは対象になりませんから。リベース後も、一連のリビジョンは依然として mq に紐付いており、 mq で管理された先のリビジョンへ戻って編集することができます。

6. チュートリアル

mq について詳しくは MqTutorial をご覧ください。

7. フックの例

たいていの場合は、パッチを適用したリポジトリから変更内容を push または pull したくないでしょう。 うっかりやってしまわないように、 hook をリポジトリの .hg/hgrc へ追加しましょう。

Mercurial 0.9.2 以降では、 --force オプションなしで push することはありません。 -- ThomasArendsenHein 2007-01-05 08:36:33

[hooks]
# MQ パッチ適用中 は "hg pull" を防止
prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&1
# MQ パッチ適用中 は "hg push" を防止
preoutgoing.mq-no-push = ! hg qtop > /dev/null 2>&1

Mercurial 2.1 以降では、 mq secret フェーズサポート を使ってみるとよいでしょう。

8. コマンドの例

cd some_existing_hg_repository

# パッチキュー・ディレクトリをセットアップ (Mercurial 1.5 で非推奨に)
hg qinit

# firstpatch という名前のパッチを作る
hg qnew firstpatch

# ファイルを変更
vi filename

# 変更内容でパッチを更新
hg qrefresh

# vi .hg/patches/firstpatch で結果を見て
# 現在のパッチの内容を画面に出力
hg qdiff

# さらに変更
vi filename

# パッチに保存されていない差異を見る
hg diff

# パッチを更新
hg qrefresh

# 別のパッチを作る
hg qnew secondpatch

# さらなる変更を加え、パッチを更新
vi filename
hg qrefresh

# 適用中のパッチを調べる
# キューにある全パッチを見る
hg qapplied
hg qseries

# 最上位のパッチを取り除く
hg qpop

# そのパッチを再度適用
hg qpush

# パッチを全て取り除く
hg qpop -a

# パッチを全て適用
hg qpush -a

9. 小ワザ

9.1. 適用中のパッチを全て E-Mail

hg email qbase:qtip

9.2. 適用中のパッチを恒久なチェンジセットへ変換

hg qfinish -a

9.3. 適用中のパッチを1つのパッチにまとめて出力

hg diff -r qparent:qtip

9.4. 一時的に作業をよけて後で再開

git stash に当たる操作は、 Mercurial ではこうなります。

hg qnew choosename
hg qpop
# ...
# restore
hg qpush
hg strip -k choosename
hg qremove choosename

9.5. パッチを常に git 拡張フォーマットに

以下を .hgrc へ追加

[diff]
git=1

9.6. qrefresh でタイムスタンプを更新しない

パッチキューをバージョン管理下に置いている場合は、 qrefresh する度にパッチのタイムスタンプが更新されてイライラするかもしれません。 タイムスタンプを更新させたくない場合は、以下を .hgrc へ追加してください。

[diff]
nodates=1

9.7. qstatus コマンドの追加方法

以下を .hgrc へ追加 (詳しくは AliasExtension を):

[alias]
qstatus = status --rev -2:.

他には "status --rev qparent:." や "status --rev qparent:qtip" というエイリアスが有用でしょう。

9.8. パッチのコミットメッセージを更新

1 行メッセージを書き換えるだけなら、こうしてください:

hg qrefresh -m "新しいメッセージ"

メッセージが複数行に及ぶ場合はこうです:

hg qrefresh -e

$EDITOR が開くのでコミットメッセージを編集してください。

9.9. パッチの公開

パッチキューで長い間操作していると、公開リポジトリを継続的に最新の変更内容で更新するのに辟易することと思います。 フックを使えば一連の処理をかなり自動化できます。 ここにリポジトリが2つあるとします。ひとつは基本のリポジトリで、もうひとつは hg qinit -c で作成するようなパッチのリポジトリです。

パッチリポジトリ(メインリポジトリのルートの中、 .hg/patches)に、次の changegroup フックをセットアップしましょう:

[hooks]
# 最新バージョンのパッチをチェックアウト
changegroup.1update = hg update
# ベースリポジトリから古いバージョンを pop
changegroup.2pop = hg -R ../.. qpop -a
# 今チェックアウトしたところのバージョンを push
changegroup.3push = hg -R ../.. qpush -a

もし手の込んだ事が好きなら, パッチ・リポジトリを別のフックで公開することもできます:

changegroup.publish = hg push ../../../patches/foo

この方法で overlay patch queuehttp://hg.kublai.com/mercurial/overlay へ公開しています。

9.10. パッチキューの変更を常に secret フェーズにする

互換性の問題で 、 mq パッチはデフォルトで secret phase になりません。つまり、パッチを他のリポジトリとやり取りできてしまいます。たいていこれは好ましくありませんから、設定で secret フェーズサポートを有効にできるようになっています:

[mq]
secret = True

10. Strip

/!\ Mercurial 2.8 以降は StripExtension を別に同梱しています。

strip コマンドはパッチキューを扱いませんが、 mq エクステンションの一部でした。

11. 関連項目

12. 外部リンク


CategoryJapanese

English

JapaneseMqExtension (last edited 2014-08-27 14:06:43 by YuyaNishihara)