foozy@708: \chapter{Advanced uses of Mercurial Queues} foozy@708: \label{chap:mq-collab} foozy@708: foozy@708: Mercurial Queues の用法を真っ正直に話題にするのは簡単ですが、 foozy@708: 少々抑制を効かせて、込み入った開発環境での作業に役立つような、 foozy@708: あまり利用されない機能を幾つか説明しようと思います。 foozy@708: foozy@708: この章では、 foozy@708: Linux カーネル向けの Infiniband デバイスドライバ開発において、 foozy@708: 管理に用いていた技法を使用例として取り上げます。 foozy@708: このデバイスドライバは foozy@708: (一般のデバイスドライバ程度には)大きく、 foozy@708: 35 のソースファイルにまたがった 25,000 行からなっており、 foozy@708: 少数の開発チームにより保守されています。 foozy@708: foozy@708: この章で扱っている対象は Linux に特化したものですが、 foozy@708: 自身が所有していないコードを元に多くの開発を行う必要がある局面で、 foozy@708: 同様の方針が適用できるでしょう。 foozy@708: foozy@708: \section{The problem of many targets} foozy@708: foozy@708: Linux カーネルは頻繁に変更され、 foozy@708: 内部的には決して安定していません。 foozy@708: 開発者はリリースの間に度々思い切った変更を行います。 foozy@708: このため、 foozy@708: Linux カーネルの特定のリリース版で機能するドライバーの版は、 foozy@708: 概して他の版においては\emph{コンパイル}すら通らない場合があります。 foozy@708: foozy@708: ドライバの保守を行うためには、 foozy@708: いくつかの個別の Linux の版を意識する必要があります。 foozy@708: foozy@708: \begin{itemize} foozy@708: \item 第一には、メインの Linux カーネル開発ツリーです。 foozy@708: この場合のコードの保守は、カーネルコミュニティの他の開発者と共有され、 foozy@708: 彼らがカーネルのサブシステムに対して行うのと同程度に、 foozy@708: ``開発しながらの''変更が行われます。 foozy@708: foozy@708: \item 開発しているドライバを利用することができない古い foozy@708: Linux ディストリビューションを使用している顧客の要望に応えるために、 foozy@708: 古い Linux カーネルの版に対する幾つかの``バックポート''の保守も必要です。 foozy@708: (コードの\emph{バックポート}には、 foozy@708: そのコードの開発対象となる版よりも古い版の環境で稼動させるための、 foozy@708: コードの改変が必要です) foozy@708: foozy@708: \item 最後になりますが、顧客の利用しているカーネルやディストリビューションの、 foozy@708: 全体に対する更新を強いることなく新規機能を提供するために、 foozy@708: ソフトウェアのリリーススケジュールは、 foozy@708: Linux ディストリビューションやカーネル開発者が利用しているカーネルと、 foozy@708: 必ずしも足並みを揃えるわけではありません。 foozy@708: foozy@708: \end{itemize} foozy@708: foozy@708: \subsection{Tempting approaches that don't work well} foozy@708: foozy@708: 複数の異なる環境を対象としなければならない一連のソフトウェアの保守には、 foozy@708: 2つの``標準的な''方法があります。 foozy@708: foozy@708: 1つ目の方法は、 foozy@708: それぞれが単一の環境を対象とする複数のブランチを管理する方法です。 foozy@708: この方法の問題点は、 foozy@708: リポジトリ間での変更の往来\footnote{訳注: いわゆる「マージ」のこと}において、 foozy@708: 鉄の規律でもって望む必要が有ることです。 foozy@708: 新しい機能やバグの修正は``真新しい''リポジトリで始めなければならず、 foozy@708: その後で全てのバックポート用リポジトリに浸透させます。 foozy@708: バックポートでの変更は、その伝播が更にブランチ限定されます。 foozy@708: 所属外のブランチに適用されるようなバックポート向けの変更は、 foozy@708: おそらくドライバのコンパイルを妨げるでしょう。 foozy@708: foozy@708: 2つ目の方法は、 foozy@708: 個々のコード片の有効/無効を、 foozy@708: 意図する対象に依存して切り替えるための条件文で埋められた、 foozy@708: 単一のソースツリーを保守する方法です。 foozy@708: これらの``ifdef''記述は、 foozy@708: Linux カーネルツリーでは許されていないので、 foozy@708: これらを取り除いて綺麗なツリーを生成するための、 foozy@708: 手動ないし自動の手順が必要です。 foozy@708: この流儀で保守されるコードベースは早々に、 foozy@708: 理解も保守も困難な条件分岐の「鼠の巣」となるでしょう。 foozy@708: foozy@708: これらのいずれの手法も、 foozy@708: 正当なソースツリーのコピーを``所有''していない状況には適合しません。 foozy@708: 標準カーネルと共に配布される Linux ドライバの場合、 foozy@708: Linus 氏のソースツリーは、 foozy@708: 世界中が正統とみなすコードのコピーから構成されます。 foozy@708: 上流リポジトリにおける``私の''ドライバは、 foozy@708: Linus 氏のソースツリー上に改変内容が反映されるまでには、 foozy@708: 知らないうちに見知らぬ人々によって異なる版に改変されているかもしれません。 foozy@708: foozy@708: これらの手法は、 foozy@708: 上流リポジトリへのパッチの体裁を整えるのを難しくしてしまう、 foozy@708: という欠点も持っています。 foozy@708: foozy@708: Mercurial Queues は、 foozy@708: これまで述べてきた状況での開発を管理するための、 foozy@708: 良い候補と言えます。 foozy@708: まさにこのような状況において、 foozy@708: MQ は作業を快適にする更に幾つかの付加的機能を持っています。 foozy@708: foozy@708: \section{ガードによる条件付きパッチ適用} foozy@708: foozy@708: おそらく、 foozy@708: 多くの対象環境に対する健全性を保守する方法は、 foozy@708: 所定の状況ごとに適用される特定のパッチを選択できること、 foozy@708: と言えるでしょう。 foozy@708: MQ は、 foozy@708: 上記の機能を持つ``ガード''(quilt の \texttt{guards} コマンドに由来します) foozy@708: と呼ばれる機能を提供します。 foozy@708: まずはじめに、 foozy@708: 実験のための簡素なリポジトリを作成しましょう。 foozy@708: foozy@708: \interaction{mq.guards.init} foozy@708: foozy@708: この手順により、 foozy@708: 異なるファイルを操作するので互いには依存性の無い2つのパッチを持つ、 foozy@708: 小さなリポジトリが得られます。 foozy@708: foozy@708: 条件付き適用の考え方は、 foozy@708: 任意の単純な文字列からなる\emph{ガード}された``札'' foozy@708: (tag)をパッチに付与しておき、 foozy@708: パッチ適用の際に、使用すべき特定のガードを MQ に対して教える、 foozy@708: というものです。 foozy@708: あらかじめ選択しておいたガードに応じて、 foozy@708: MQ はガードされたパッチを適用するか見送るかを決定します。 foozy@708: foozy@708: 個々のパッチは任意の数のガードを持つことができ、 foozy@708: それぞれのガードは\emph{ポジティブ} foozy@708: (``ガード選択時にパッチを適用する場合'')か\emph{ネガティブ} foozy@708: (``ガード選択時にパッチ適用を見送る'')のどちらかです。 foozy@708: ガードを持たないパッチは常に適用されます。 foozy@708: foozy@708: \section{パッチのガードを制御する} foozy@708: foozy@708: \hgxcmd{mq}{qguard} コマンドは、 foozy@708: どのガードをパッチに適用するかを決定するか、 foozy@708: さもなくば現時点で有効なガードを表示します。 foozy@708: 引数が無い場合、現在の最上位パッチのガードを表示します。 foozy@708: foozy@708: \interaction{mq.guards.qguard} foozy@708: foozy@708: パッチにポジティブなガードを設定するには、 foozy@708: ガード名の接頭辞として ``\texttt{+}'' を付与します。 foozy@708: foozy@708: \interaction{mq.guards.qguard.pos} foozy@708: foozy@708: パッチにネガティブなガードを設定するには、 foozy@708: ガード名の接頭辞として ``\texttt{-}'' を付与します。 foozy@708: foozy@708: \interaction{mq.guards.qguard.neg} foozy@708: foozy@708: \begin{note} foozy@708: \hgxcmd{mq}{qguard} コマンドは、パッチにガードを設定しますが、 foozy@708: パッチのガード設定を\emph{変更}したりはしません。 foozy@708: つまり、 foozy@708: パッチに \hgcmdargs{qguard}{+a +b} を適用した後に、 foozy@708: 同じパッチに \hgcmdargs{qguard}{+c} を適用した場合、 foozy@708: このパッチに設定されているガードは \texttt{+c} \emph{だけ}となります。 foozy@708: \end{note} foozy@708: foozy@708: Mercurial は、 foozy@708: 解釈・手動編集が共に容易な形式で、 foozy@708: ガード情報を \sfilename{series} に格納します foozy@708: (言い換えるなら、 foozy@708: \hgxcmd{mq}{qguard} コマンドを利用する必要は無く、 foozy@708: \sfilename{series} ファイルを直接編集しても構いません)。 foozy@708: foozy@708: \interaction{mq.guards.series} foozy@708: foozy@708: \section{使用するガードの選択} foozy@708: foozy@708: \hgxcmd{mq}{qselect} コマンドは、有効にするガードを決定します。 foozy@708: ガードが決定することで、 foozy@708: 次に \hgxcmd{mq}{qpush} を実行した際に MQ が適用するパッチが決定されます。 foozy@708: このコマンドはそれ以外の働きをしません。 foozy@708: 特に、既に適用済みのパッチに対しては、一切何も行いません。 foozy@708: foozy@708: 引数が指定されない場合、 foozy@708: \hgxcmd{mq}{qselect} コマンドは、 foozy@708: 現時点で有効になっているガードを1行に1つづつ表示します。 foozy@708: 個々の引数は、適用されるガードの名前とみなされます。 foozy@708: foozy@708: \interaction{mq.guards.qselect.foo} foozy@708: foozy@708: 現在選択されているガードの一覧が foozy@708: \sfilename{guards} ファイルに格納されていますので、 foozy@708: 興味があれば見てみるのも良いでしょう。 foozy@708: foozy@708: \interaction{mq.guards.qselect.cat} foozy@708: foozy@708: \hgxcmd{mq}{qpush} を実行することで、 foozy@708: ガード選択の効果を見ることができます。 foozy@708: foozy@708: \interaction{mq.guards.qselect.qpush} foozy@708: foozy@708: foozy@708: ``\texttt{+}'' ないし ``\texttt{-}'' foozy@708: で始まる名前はガード名にはできません。 foozy@708: 空白文字を含むものもガード名にはなれませんが、 foozy@708: それいがいの大抵の文字は使用可能です。 foozy@708: 不正なガード名の使用は、MQ により警告されます。 foozy@708: foozy@708: \interaction{mq.guards.qselect.error} foozy@708: foozy@708: ガード選択の変更は、適用されるパッチを切り替えます。 foozy@708: foozy@708: \interaction{mq.guards.qselect.quux} foozy@708: foozy@708: ネガティブなガードがポジティブなガードに優先することを、 foozy@708: 以下の例で見ることができます。 foozy@708: foozy@708: \interaction{mq.guards.qselect.foobar} foozy@708: foozy@708: \section{MQ のパッチ適用ルール} foozy@708: foozy@708: パッチ適用の有無を判定する際に、MQ は以下のルールを使用します。 foozy@708: foozy@708: \begin{itemize} foozy@708: \item ガード無しパッチは常に適用されます。 foozy@708: foozy@708: \item 現在選択されているガードにマッチするネガティブガードがある場合、 foozy@708: パッチは適用されません。 foozy@708: foozy@708: \item 現在選択されているガードにマッチするポジティブガードがある場合、 foozy@708: パッチは適用されます。 foozy@708: foozy@708: \item 現在選択されているガードにマッチするガードが何も無い場合、 foozy@708: パッチは適用されません。 foozy@708: foozy@708: \end{itemize} foozy@708: foozy@708: \section{Trimming the work environment} foozy@708: foozy@708: 先に述べた foozy@708: Linux カーネル向けの Infiniband foozy@708: デバイスドライバ開発でのパッチ適用では、 foozy@708: Linux カーネルの通常のソースツリーは使用しません。 foozy@708: その代わり、 foozy@708: Infiniband デバイスドライバ開発に関連するソース/ foozy@708: ヘッダのみを含むリポジトリを作成し、 foozy@708: そこに対してパッチを適用するようにします。 foozy@708: このリポジトリのサイズはカーネルリポジトリの 1\% に収まるため、 foozy@708: 作業を行うのも簡単です。 foozy@708: foozy@708: 縮小版のリポジトリを作成したならば、 foozy@708: パッチの``適用対象''となるバージョンを選択します\footnote{訳注: foozy@708: ここで言う「choose」(選択)は、 foozy@708: \hgcmd{update} 実行を指すのではないか? foozy@708: そうであれば、次文が「これは〜スナップショットだ」というのも理解できる。}。 foozy@708: XXXXXXXXXXXX foozy@708: This is a snapshot of the Linux kernel tree as of a revision foozy@708: of my choosing. foozy@708: XXXXXXXXXXXX foozy@708: 適用対象を選択する際に筆者は、 foozy@708: 当該リビジョンのカーネルリポジトリにおけるチェンジセットIDを、 foozy@708: コミットメッセージ\footnote{訳注: パッチの? XXXXXX}中に記録しておきます。 foozy@708: カーネルツリー中の開発に関連する部位に関して、 foozy@708: スナップショットによって``状況''と内容が特定できるため、 foozy@708: 縮小版リポジトリと通常版のカーネルツリーのいずれに対しても、 foozy@708: パッチの適用が可能になります。XXXXXX foozy@708: Since the snapshot foozy@708: preserves the ``shape'' and content of the relevant parts of the foozy@708: kernel tree, I can apply my patches on top of either my tiny foozy@708: repository or a normal kernel tree. foozy@708: foozy@708: 通常は、 foozy@708: パッチの適用対象となるソースツリーのベースには、 foozy@708: 上流リポジトリの直近のスナップショットを使用すべきです。 foozy@708: そうすることで、 foozy@708: 作成したパッチを上流リポジトリの担当者へ送付する際に、 foozy@708: 殆ど(あるいは全く)改変の必要が無くなるでしょう。 foozy@708: foozy@708: \section{Dividing up the \sfilename{series} file} foozy@708: foozy@708: 筆者は、\sfilename{series} に列挙されるパッチを、 foozy@708: 幾つかの論理的なまとまりに分類しています。 foozy@708: それぞれのパッチ分類は、 foozy@708: その後に列挙されるパッチの意図を記述したコメントブロックで開始されます。 foozy@708: foozy@708: 筆者の扱っているパッチ分類は、以下のような並びになっています。 foozy@708: 分類の順序は重要なので、分類を紹介した後で説明します。 foozy@708: foozy@708: \begin{itemize} foozy@708: \item ``受理済み(accepted)''分類: foozy@708: 開発チームが Infiniband サブシステムの保守担当に送付して、 foozy@708: 既に受理はされているものの、 foozy@708: 縮小版リポジトリが元にしているスナップショットには、 foozy@708: まだ反映されていないパッチの分類です。 foozy@708: これらは、 foozy@708: 上流リポジトリの保守担当のリポジトリと同じ状態を得るために、 foozy@708: ソースツリーを変換する``読み出し限定''パッチです。 foozy@708: foozy@708: \item ``再作業(rework)''分類: foozy@708: 上流リポジトリの保守担当に送付したものの、 foozy@708: 受理に当たって変更を要求されたパッチの分類。 foozy@708: foozy@708: \item ``保留(pending)''分類: foozy@708: 上流リポジトリの保守担当に送付こそしていないものの、 foozy@708: 既に作業を終えたパッチの分類。 foozy@708: しばらくの間は``読み出し限定''として扱われます。 foozy@708: 上流リポジトリの保守担当により受理されれば、 foozy@708: このパッチを``受理済み''分類の末尾へと移動します。 foozy@708: 受理に当たって変更が要求された場合、 foozy@708: ``再作業''分類の先頭へと移動します。 foozy@708: foozy@708: \item ``作業中(in progress)''分類: foozy@708: 目下のところ活発に作業が行われているパッチの分類。 foozy@708: この分類のパッチは、外部に公開すべきではありません。 foozy@708: foozy@708: \item ``バックポート(backport)''分類: foozy@708: 古い版のカーネルのソースツリーに適合させるためのパッチの分類。 foozy@708: foozy@708: \item ``内部用(do not ship)''分類: foozy@708: 何らかの理由により、上流リポジトリの保守担当へは送付されないパッチの分類。 foozy@708: このようなパッチの例としては、 foozy@708: ドライバ識別用の埋め込み文字列の変更を行うことで、 foozy@708: ソースツリーのものとは異なるドライバ実装の版 foozy@708: \footnote{訳注: 開発中のドライバのこと?}と、 foozy@708: ディストリビューションベンダによって配布されるドライバ実装の版の間で、 foozy@708: 動作確認等における区別を容易にするパッチがあります。 foozy@708: foozy@708: \end{itemize} foozy@708: foozy@708: ではここで、パッチ分類尾をこの順番にする理由に戻りましょう。 foozy@708: コンテキストの変更が発生することで、 foozy@708: スタック上方のパッチへの再作業 foozy@708: \footnote{訳注: \hgxcmd{mq}{qrefresh} の実行によるパッチの修正のこと} foozy@708: が必要になることが無いように、 foozy@708: スタック中で底にあるパッチほど安定していて欲しいものです。 foozy@708: 変更されにくいパッチ群を foozy@708: \sfilename{series} ファイルの冒頭に置くことで、 foozy@708: この目的を達成することができます。 foozy@708: foozy@708: 他のパッチの適用を極力上流リポジトリの状態に近いソースツリーへ行うために、 foozy@708: ソースツリーの変換に必要と思われるパッチも重要です。 foozy@708: 受理済みのパッチも暫くの間保持しているのはそのためです。 foozy@708: foozy@708: ``バックポート''および``内部用''パッチは、 foozy@708: \sfilename{series} 末尾近辺を転々とします。 foozy@708: バックポートパッチは他の全てのパッチ適用の上で適用されなければなりませんし、 foozy@708: その上、 foozy@708: ``内部用''パッチは不都合が無いように内部に留まり続ける必要があります。 foozy@708: foozy@708: \section{Maintaining the patch series} foozy@708: foozy@708: 筆者の作業の際には、 foozy@708: パッチ適用を制御するために複数のガードを使用しています。 foozy@708: foozy@708: \begin{itemize} foozy@708: \item ``受理済み''パッチには、\texttt{accepted} ガードが付与されます。 foozy@708: このガードは殆どの場合に有効とされます。 foozy@708: 既にパッチが適用されているソースツリーにパッチを適用する際には、 foozy@708: パッチを適用させないようにすることが foozy@708: \footnote{訳注: \texttt{accepted} ガード付きパッチを無効にすることで} foozy@708: できるので、 foozy@708: 後続のパッチ群は綺麗に適用されます。 foozy@708: foozy@708: \item 作業は``完了''しているものの、 foozy@708: 上流リポジトリの保守担当に送付されていないパッチ foozy@708: \footnote{訳注: 先の分類で言うところの``保留(pending)''}には、 foozy@708: 何もガードが付与されません。 foozy@708: 上流リポジトリのコピーに対してパッチスタックを適用する場合、 foozy@708: 特に何もガードを指定しなくても、 foozy@708: 適度に安全なソースツリーを得ることができます。 foozy@708: foozy@708: \item 上流リポジトリの保守担当への(再)送付に当たって、 foozy@708: 再作業が必要なパッチには \texttt{rework} ガードが付与されます。 foozy@708: foozy@708: \item 目下開発作業中にあるパッチ foozy@708: \footnote{訳注: 先の分類で言うところの``作業中(in progress)''}には、 foozy@708: \texttt{devel} ガードが付与されます。 foozy@708: foozy@708: \item バックポートパッチには、 foozy@708: 適用対象カーネルのバージョンを指定する複数のガードが付与されます。 foozy@708: 例えば、~2.6.9 版へのバックポートを行うパッチには、 foozy@708: \texttt{2.6.9} ガードが付与されます。 foozy@708: foozy@708: \end{itemize} foozy@708: foozy@708: これらのガード分類により、 foozy@708: 最終的にどのようなソースツリーが得られるかを決定する際に、 foozy@708: 少なからぬ柔軟性を得ることができます。 foozy@708: 多くの場合、 foozy@708: 適切なガードの選択は構築手順の中で自動化されていますが、 foozy@708: 特別な状況向けにガードの調整を手動で行うことも可能です。 foozy@708: foozy@708: \subsection{The art of writing backport patches} foozy@708: foozy@708: MQ を使用することで、 foozy@708: バックポートパッチの作成は単純な作業となります。 foozy@708: 旧版のカーネル配下においてもドライバが正常に稼動するように、 foozy@708: 旧版のカーネルにおいて提供されていない機能を使用するコードの変更が、 foozy@708: バックポートパッチのすべきことの全てです。 foozy@708: foozy@708: 良いバックポートパッチを書く際のゴールは、 foozy@708: 対象とする旧版カーネル向けに書いたかのように、 foozy@708: あなたのコードを変更するようなパッチにすることです。 foozy@708: パッチがでしゃばらない程、理解と保守が容易になります。 foozy@708: コード中の大量の \texttt{\#ifdef}(条件に応じて適用されるコード片) foozy@708: による``鼠の巣''化を避けるためにバックポートパッチ群を書くのであれば、 foozy@708: バージョン依存な \texttt{\#ifdef} をパッチに持ち込むべきではありません。 foozy@708: バージョン依存な \texttt{\#ifdef} を使用する替わりに、 foozy@708: 個々のパッチはバージョンに依存しない変更を行うようにして、 foozy@708: パッチの適用をガードによって制御すべきです。 foozy@708: foozy@708: ``通常''のパッチと、 foozy@708: その適用結果を更に変更するバックポートパッチとを、 foozy@708: 別個のグループに分離するのには2つの理由があります。 foozy@708: 第1の理由は、 foozy@708: これらのパッチが混ざり合った場合に、 foozy@708: 上流リポジトリの保守担当へのパッチ送付の自動化の際に、 foozy@708: \hgext{patchbomb} 拡張のようなツールを使うことが難しくなるためです。 foozy@708: 第2の理由は、 foozy@708: 後続の通常パッチの適用コンテキスト foozy@708: \footnote{訳注: \command{patch} ファイルにおける「コンテキスト」} foozy@708: をバックポートパッチが混乱させてしまい、 foozy@708: 通常パッチの適用前に適用されたバックポートパッチ\emph{抜き}では、 foozy@708: 通常パッチを綺麗に適用することができなくなってしまうためです。 foozy@708: foozy@708: \section{Useful tips for developing with MQ} foozy@708: foozy@708: \subsection{Organising patches in directories} foozy@708: foozy@708: MQ を利用した実在するプロジェクトで作業をしているのであれば、 foozy@708: 多くのパッチを蓄積することも難しいことではありません。 foozy@708: 例えば、筆者は 250 を超えるパッチを抱えたパッチリポジトリを持っています。 foozy@708: foozy@708: パッチを個別の論理的なまとまりに分類できるのであれば、 foozy@708: MQ はパッチ名にパス区切りが含まれていても問題ないので、 foozy@708: それぞれのパッチを異なるディレクトリに格納することもできます foozy@708: \footnote{訳注: MQ はパッチ内容の保存先として、 foozy@708: パッチ名と同名のファイルを作成するため、 foozy@708: パッチ名にパス区切りが含まれる場合、 foozy@708: MQ は自動的にサブディレクトリを作成します}。 foozy@708: foozy@708: \subsection{Viewing the history of a patch} foozy@708: \label{mq-collab:tips:interdiff} foozy@708: foozy@708: 長期間にわたってパッチの開発を行う場合、 foozy@708: \ref{sec:mq:repo} 節で述べたように、 foozy@708: パッチをリポジトリで管理するのが良いでしょう。 foozy@708: その場合は早々に、 foozy@708: パッチの変更履歴の参照に foozy@708: \hgcmd{diff} が使えないことに気付くことでしょう。 foozy@708: これは実際のコードの二次派生物(差分の差分)を見ていること以外にも、 foozy@708: タイムスタンプやパッチ更新時のディレクトリ名等を改変することで foozy@708: MQ が雑音を加えてしまっていることに原因があります。 foozy@708: foozy@708: Mercurial に同梱されている \hgext{extdiff} 拡張を使うことで、 foozy@708: 2つの版のパッチ差分を幾分読みやすいものにすることができます。 foozy@708: この拡張を使うためには、 foozy@708: サードパーティーパッケージである foozy@708: \package{patchutils}~\cite{web:patchutils} が必要です。 foozy@708: このパッケージが提供する \command{interdiff} というコマンドは、 foozy@708: 差分間の差分を1つの差分として表示します。 foozy@708: 同じ差分の2つの版 foozy@708: \footnote{訳注: 「同じパッチの異なる版」の意か?} foozy@708: に対してこのコマンドを適用すると、 foozy@708: 最初の版から次の版へと変更するための差分を生成します。 foozy@708: foozy@708: いつものように、 foozy@708: \hgrc ファイルの \rcsection{extensions} foozy@708: セクションに行を追加することで、 foozy@708: \hgext{extdiff} 拡張を有効化することができます。 foozy@708: foozy@708: \begin{codesample2} foozy@708: [extensions] foozy@708: extdiff = foozy@708: \end{codesample2} foozy@708: foozy@708: \command{interdiff} コマンドは2つのファイル名の指定が必要ですが、 foozy@708: \hgext{extdiff} 拡張は、 foozy@708: それぞれ任意の数のファイルを配下に持つ、 foozy@708: 2つのディレクトリに対して動作するプログラムの指定が必要です。 foozy@708: そのため、 foozy@708: これら2つのディレクトリ配下の個々のファイル対に対して foozy@708: \command{interdiff} を実行する小さなプログラムが必要です。 foozy@708: 本書のソースコードリポジトリにおける foozy@708: \dirname{examples} ディレクトリ配下に、 foozy@708: \sfilename{hg-interdiff} として格納されています。 foozy@708: foozy@708: \excode{hg-interdiff} foozy@708: foozy@708: \sfilename{hg-interdiff} がシェルのコマンド検索パス上に有る場合、 foozy@708: MQ のパッチディレクトリから以下のようにして起動することができます。 foozy@708: foozy@708: \begin{codesample2} foozy@708: hg extdiff -p hg-interdiff -r A:B my-change.patch foozy@708: \end{codesample2} foozy@708: foozy@708: おそらくこの長たらしいコマンドを何度も使うことになるでしょうから、 foozy@708: 再度 \hgrc を編集して、 foozy@708: \hgext{hgext} を Mercurial の普通のコマンド並に使えるようにしましょう。 foozy@708: foozy@708: \begin{codesample2} foozy@708: [extdiff] foozy@708: cmd.interdiff = hg-interdiff foozy@708: \end{codesample2} foozy@708: foozy@708: この記述により \texttt{interdiff} が foozy@708: \hgext{hgext} から利用できるようになりますので、 foozy@708: 先の \hgxcmd{extdiff}{extdiff} 起動も短くなって幾分使いやすくなるでしょう。 foozy@708: foozy@708: \begin{codesample2} foozy@708: hg interdiff -r A:B my-change.patch foozy@708: \end{codesample2} foozy@708: foozy@708: \begin{note} foozy@708: \command{interdiff} コマンドは、 foozy@708: 場合だけ正しく機能します。 foozy@708: The \command{interdiff} command works well only if the underlying foozy@708: files against which versions of a patch are generated remain the foozy@708: same. foozy@708: パッチの生成・ファイルの変更およびパッチの更新を行った場合、 foozy@708: \command{interdiff} は有用な出力を生成しないことがあります。 foozy@708: \end{note} foozy@708: foozy@708: \hgext{extdiff} 拡張は、 foozy@708: MQ パッチの表示機能の向上に留まらない有用なものです。 foozy@708: \hgext{extdiff} 拡張に関する詳細は、 foozy@708: \ref{sec:hgext:extdiff} 節を参照してください。 foozy@708: foozy@708: %%% Local Variables: foozy@708: %%% mode: latex foozy@708: %%% TeX-master: "00book" foozy@708: %%% End: