The Hackerlab at regexps.com

チェンジセット (changeset) の紹介

up: arch Meets hello-world
next: チェンジセットの探究
prev: update/commit を使った共同作業

二つのプロジェクトツリー(ふつうは同じプロジェクトの)を比較し、 それらの間で変化したものを正確に考えることは, しばしば非常に有用です。 そのような変更の記録は チェンジセット (changeset) あるいは デルタ (delta) と呼ばれます。

チェンジセットは arch の最も中心的な概念です。 arch の多くはチェンジセットと共に実行される操作で定義されます。

"古いツリー"と"新しいツリー"の間の チェンジセットを持っていれば、 古いツリーに"このチェンジセットを適用して", 新しいツリーを得ることができます. 言い換えると、チェンジセットにより記述された変更を自動的に加えることができます. 三番目のツリーを持っていれば、パッチを適用して三番目のツリーに 同じ変更をすることが近似的にできます.

archは、チェンジセットを作成し適用するための精巧なツールを含みます.


mkpatch

up: チェンジセット (changeset) の紹介
next: dopatch

mkpatch は、2つのツリーのあいだの違いを記述するチェンジセットを計算します。 基本的なコマンドの文法は次のとおりです:

        % tla mkpatch ORIGINAL MODIFIED DESTINATION

これは ORIGINAL ツリーと MODIFIED ツリーを比較します.

mkpatch は新しいディレクトリである, DESTINATION を作成し、チェンジセットをそこに格納します。

mkpatch がツリーを比較する場合、インベントリ id を使います。 例えば、二つのディレクトリ, あるいは, 二つのファイルは, それらが同じ idを持っている場合、"同じディレクトリ(あるいはファイル)" とみなします. これは, それぞれが各々のツリーのどこにあるかは関係しません. (ソースのインベントリ Id を参照.)

mkpatch によって生成されたチェンジセットが記述することは、 どのファイルおよびディレクトリが追加されたり削除されたか, どれが改名され、どのファイルが変更されたか(そしてどのように変更されたか)、 またどのファイルのパーミッションが変化したか(かつどのように)です. 通常のテキストファイルを比較する場合、 mkpatch は差異を記述するコンテキスト diff を生成します。 mkpatch はバイナリファイルを比較することも (新旧バージョンが異なる場合、それらの完全なコピーを保存します), シンボリックリンクを比較することもできます (新旧リンクターゲットが異なる場合、 それらを保存します).

チェンジセットのフォーマットの詳細な記述は付録にて提供されます (arch のチェンジセットフォーマットを参照).


dopatch

up: チェンジセット (changeset) の紹介
next: 不正確なパッチ -- いかに衝突を処理するか
prev: mkpatch

dopatch はチェンジセットをツリーに適用するのに使います:

        % tla dopatch PATCH-SET TREE

もし, treemkpatchの調べた "修正前"のツリーと正確に同じものであるなら, その効果は treeを変更させて mkpatchの調べた "修正後"ツリーと正確に同じにするでしょう. ただし, 一点の例外を 除きます (説明は以下).

"正確に同じ"が意味することは、ディレクトリ構造が同じであり, シンボリックリンクターゲットが同じ、通常のファイルの内容が同じで、 ファイルパーミッションが同じであることです。 変更時刻、複数の(ハード)リンクを持つファイル, およびファイル所有権は、 確実には保存されません。

"正確に同じ"の規則の例外は、 もしパッチが要求することが, ファイルやディレクトリが treeから取り除かれることである場合, これらのファイルとディレクトリは treeのサブディレクトリに保存され, そのサブディレクトリの名前は, 目の割れるような, 次のパターンに一致します:

        ++removed-by-dopatch-PATCH--DATE

ここで, PATCHはパッチセットディレクトリの名前であり、 DATEはタイムスタンプです。


不正確なパッチ -- 衝突をいかに処理するか

up: チェンジセット (changeset)の紹介
prev: dopatch

dopatch がパッチを当てたツリーが, mkpatch によって調べられた修正前のツリーと正確に同じでは 無いとするとどうなるでしょう?

以下は、何を期待するかについての手短な記述です。 dopatch プロセスの完全な資料はソースコードに含まれてます。

dopatch は、パッチの対象となるツリーのインベントリを取得します. インベントリ id を使って, どのファイルとディレクトリがツリーに存在するか 不在であるかがチェンジセットで予定されてるかを決定し, ファイルとディレクトリが ツリーのどこにあるかを計算します.

単純なパッチ (Simple Patches) チェンジセットが 通常のパッチや, リンク, ディレクトリあるいはファイルのメタデータを持っていて, そのファイルがツリーに存在するなら, dopatchはそのパッチを 普通の方法で適用します. もしパッチをクリーンに適用したら, 変更後のファイル, リンク, ディレクトリは そこに残ります.

もし単純なパッチがクリーンに適用できないとき, dopatch は常に .orig ファイル (ツリー下のパッチ対象の適用前のファイルで, 変更無しのもの)と, .rej ファイル (適用できなかったパッチの一部分)を残します.

もしパッチがコンテキスト diff ならば、 dopatch はさらにファイル自体を残すでしょう -- 部分的にパッチを当てて.

もし(失敗した)パッチがバイナリー・ファイルに対してのものなら, 部分的にパッチ当てされたファイルは残りません. 代わりに, そこに残るのは:

        .orig   -- パッチ対象のツリーに元からあるファイル,
                   変更無し.

        .rej    -- 変更後のツリーからのファイルの完全なコピーで,
                   パーミッションは `.orig'からのコピー.

        .patch-orig -- `mkpatch'をした修正前のツリーのファイルの
                       完全なコピーで, パーミッションは修正前のまま

                        もしくは

                       `mkpatch'を使ったときの修正前のツリーの
                       シンボリックリンクで, パーミッションは
                       修正前のツリーと同じ.



もし(失敗した)パッチがシンボリックリンクに対するものなら、 部分的にパッチの当たったファイルは残りません. 代わりに, そこに残るのは:

        .orig   -- 修正前のツリーからの無修正ファイル

        .rej    -- パッチ対象のシンボリックリンクで, パーミッションは
                   .orig と同じもの

        .patch-orig -- `mkpatch'を動作させたときの修正前のツリーからの
                       完全なコピーで, パーミッションは修正前のに
                       保たれている

                        もしくは

                       `mkpatch'を動作させたときの修正前のツリーにあった
                       シンボリックリンクで, パーミッションは修正前のツリーと
                       同じ



存在しないファイルへのパッチ

存在しないファイルとディレクトリへのパッチはすべて、 パッチの当たったツリーのルートのサブディレクトリに格納されます. このディレクトリ名はは次のものです

        ==missing-file-patches-PATCH-DATE

ここで PATCHはチェンジセットディレクトリのベースネームであり、 DATEはタイムスタンプです。

ディレクトリの再配置と新ディレクトリ

ディレクトリは, 期待するとおり, 追加されたり, 削除されたり, 再配置されます. たとえ期待することが何かを知らないでもです.

mkpatch が呼ばれたときに, ORIGINAL ツリーが次のものを持ってたとしましょう:

        Directory or file:              Id:

        a/x.c                           id_1
        a/bar.c                         id_2


しかし、MODIFIEDツリーは次のようになっています:

        a/x.c                           id_1
        a/y.c                           id_2

両方のファイルに変更があります. パッチは id が id_2であるファイルの名前を y.cにして, id が id_1id_2のファイルの内容を変えることを 要求するでしょう.

例えば、次のようなツリーを持っているとします:

        a/foo.c                         tag_1
        a/zip.c                         tag_2

そして、そのツリーにパッチを適用します。パッチ後は、次が残ります:

        a/foo.c                         tag_1
        a/y.c (was zip.c)               tag_2

両方のファイルの内容にパッチが当たります.

次は, 微妙な点と衝突の取扱の例です:

mkpatch が使われたときの修正前のツリーが次のような具合だとします:

        Directory or file:              Id:

        ./a                             id_a
        ./a/b                           id_b
        ./a/b/c                         id_c


そして、修正後のディレクトリの様子は:

        ./a                             id_a
        ./a/c                           id_c
        ./a/c/b                         id_b

最後に, 問題のツリーの様子は以下だとします:

        ./x                             id_a
        ./x/b                           id_b
        ./x/c                           id_new_directory
        ./x/c/b                         id_different_file_named_b
        ./x/c/q                         id_c

パッチをそのツリーで当て終えたとき、次のようになります:

        ./x                             id_a
                これは, パッチは id_a のディレクトリは
                何も変化させないため.

        ./x/c.orig                      id_new_directory
        ./x/c.rej                       id_c
                パッチは id_c のディレクトリを名前が "c" で
                id_a のサブデイレクトリとすることを要求します. しかし,
                このツリーはすでに id が id_new_directoryである
                別のディレクトリを持っているためです.

        ./x/c.rej/b                     id_b
                パッチは id_b のディレクトリ名を変えて "b" となる,
                id_c のディレクトリのサブディレクトリにすることを要求する
                ためです.

        ./x/c.orig/b                    id_different_file_named_b
                パッチはこのファイルに新しい変更を施し,
                その親ディレクトリの下に居つづけさせるためです.

                
arch Meets hello-world: A Tutorial Introduction to The arch Revision Control System
The Hackerlab at regexps.com