TODO 基調講演がここらへんのネタなのでおまけとして
TODO Subversionその他集中型との差異について
TODO 思いの丈をぶつけます
SCM ツールにおいて、 作成/改変/移動/削除といったファイルに対する作業内容や、 実施者/日付といった 「履歴」 (history) に関する管理情報を格納しておく領域を、 (狭義の)「リポジトリ」 (repository) と呼びます。
リポジトリに格納されている情報を元に、 ファイルを取り出したり、 取り出したファイルに対する作成/改変/移動/削除といった作業を行う領域を、 CVS や Subversion では 「ワーキングコピー」 (working copy) 、 『パターンによるソフトウェア構成管理』では 「プライベートワークスペース」 (private workspace) などと呼びますが、 Mercurial では「作業領域」 (working directory) と呼びます。
CVS や Subversion では、 リポジトリからの「チェックアウト」 (checkout) によって作業領域が作成されます。
作業領域には、 ごくわずかの管理情報 (例: 各ディレクトリの CVS/* や .svn/*) しか保存されないため、 履歴情報の参照/変更が必要になった際には、 基本的に常にチェックアウト元のリポジトリに対して (場合によってはネットワーク経由で) 問い合わせが発生します。
その一方 Mercurial の場合は、 作業領域とリポジトリは一体化しており、 この「作業領域と一体になったリポジトリ」も、 広義の意味で「リポジトリ」と呼んでいます。
CVS や Subversion では、 たとえリポジトリが空であっても、 「リポジトリ」を作って「作業領域」にチェックアウトする、 という手順を踏む必要がありますが、 Mercurial では (当面一人で新規の作業するのであれば) リポジトリの新規作成を行うコマンド ("hg init") を事項したなら、 即座に作業領域として使用することができます。
「(狭義の)リポジトリ」と「作業領域」が一体となっているため、 「(狭義の)リポジトリへの履歴情報の問い合わせ」も、 手元の(広義の)リポジトリの中で完結します。
リポジトリ間での連携は、 他のリポジトリ(= 他の作業/他の人/他の拠点等) における作業成果を、 自身のリポジトリに取り込みたい場合や、 自身の成果を他のリポジトリに公開したい場合にのみ、 必要となります。
共同作業の成果を共有する場合、 作業領域にファイルを取り出さない/作業しないようにして、 「狭義のリポジトリ」のみで運用する、 いわゆる「マスターリポジトリ」を設置するのが一般的です。
既に記録された誰かの成果を元に作業を開始する場合は、 リポジトリの新規作成 ("hg init") ではなく、 「マスターリポジトリ」からの複製 ("hg clone") によって、 自分用の(広義の)リポジトリを作成するのが一般的です。
構成管理における、変更履歴の記録単位。 リビジョンの連なりによって、 作業の履歴が形成されます。 各リビジョン毎に以下の内容が記録されます:
※ 実行例(!!!!後で差し替えてください!!!!) チェンジセット: 359:a0fbbc6ba9e4 タグ: tip ユーザ: FUJIWARA Katsunori日付: Thu Oct 20 17:32:13 2011 +0900 要約: Solaris Internals ch9 まとめ資料を更新 (〜 9.5)
CVS 以前の SCM ツールでは、 ファイル毎にリビジョンの記録を管理していたため、 「ファイルに対する変更内容」の管理がファイル毎にばらばらでした。
しかし、SVN からは、記録の管理単位が 「(利用者にとって)意味を持つ、 一連のファイルへの変更のまとまり」となったことで、 これを「変更内容の集合」の意味から 「チェンジセット」(changeset)と呼ぶようになりました。
また、変更内容を履歴に記録する際のコマンド名が 「コミット」 (commit) であることから、 「リビジョン」「チェンジセット」「コミット」は多くの場合、 同等の意味を持ちます。
Mercurial のメッセージ日本語化では、 基本的に「リビジョン」に統一しています。 が、"hg log" の出力では、原文に倣って「チェンジセット」を使用しています ... orz (by 藤原)
以下の情報の記録は、リビジョンに対してではなく、 管理ファイルに別途記録されます。
Mercurialでは次の方法でリビジョンを一意に指定出来ます。
「完全長」ないし「短縮」ハッシュ値は、 「チェンジセットID」(changeset ID)とも呼ばれます。
ハッシュ値による識別は、 基本的にリポジトリをまたいでユニークですが、 リビジョン番号は手元のリポジトリでのみ有効な番号ですので、 全く同じリポジトリを操作している時以外に、 他の人との会話で使用すると、 混乱の元になりますから注意しましょう。
※ 完全長ハッシュ値は確実にユニーク。 短縮ハッシュ値は「まぁまぁ」ユニークな点に注意
特定のリビジョンに対して、 人が認識しやすい名前を付ける機能が「タグ」 (tag) 付け機能です。 タグが付いているリビジョンに関しては、上記の3種類以外に、 タグ名を使ってリビジョンを指定することも可能です。
通常のタグ付けは、 一旦設定したなら基本的には対象リビジョンに固定されますが、 「一番最新」のリビジョンを指す "tip" というタグは、 リビジョンが増える度に Mercurial が自動的に設定対象を更新します。
一つのリビジョンではなく、リビジョンの集合を指定したい場合、 旧来の簡易表記方式 ("hg help multirevs" 参照) と:
# リビジョン番号 3 からリビジョン番号 10 までを表示 $ hg log -r 3:10
集合の条件を簡単に記述する為の DSL (Domain Specific Language) である revsets (revision sets) 方式 ("hg help revsets" 参照) の2種類で指定可能です。
# "指定したブランチの先祖を新しい順で、ただしマージコミットは除く" # リビジョンのログを出力 $ hg log -r "reverse(ancestors('BRANCH_NAME')) and not merge()"
古い順から、リビジョン A、B、C の順で履歴が記録されている場合、 A は B、B は C の親リビジョンとなります。
作業領域の内容が、リビジョン C の状態になっているとします。 この時、「リビジョン C は作業領域の親リビジョンである」と言えます。
このような表現をするのは、この状態で作業領域で作業 (ファイルの改変/追加等) を行い、 作業結果を記録 (= コミット) した場合、 新規に作成されるリビジョンの親は C になるからです。作業領域を「次に作成される仮想的なリビジョンの格納場所」と考えれば、 より理解できるのではないでしょうか。
コミットを積み重ねることで、 リビジョン記録のグラフ (= 履歴) が作成されます。
リビジョングラフの中で、 子リビジョンを持たないリビジョンの事を 「ヘッド」 (HEAD) と呼びます。 次のグラフではリビジョン2がヘッドです。
ヘッド「でない」リビジョンを親にして、 新たなリビジョンを生成することを、 Mercurial では(広義の)「ブランチ」 (branch: 枝分かれ) と呼びます。 原文では "topological branch" などと呼ばれています。
以下の履歴ツリーで言えば、 リビジョン 2 の後で生成されたリビジョン 3 はブランチになります。
ヘッドを親にして新たなリビジョンを作成した場合は、ブランチになりません。
ブランチによってヘッドが複数ある状態を、 「マルチプルヘッド」 (multiple heads) と呼びます。
※ グラフを画像化/色分け
※ "hg parents" での複数親表示の例
Mercurial では、 枝分かれ元と枝分かれ先を識別するために、 枝分かれ先に名前を付けることができます。 このように名前をつけられたブランチを「名前付きブランチ」 (named branch) と呼びます。
以下の履歴グラフでは、 リビジョン 3 が "RELEASE" という名前付きブランチに属します。
CVS や Subversion 等の多くの SCM ツールで言うところの「ブランチ」は、 Mercurial での「名前付きブランチ」とほぼ等価と考えてよいでしょう (厳密には色々違いますが....)。
その一方で、 これまでの説明で使用してきた、 名前付き「ではない」ブランチは 「名前無しブランチ」 (anonymous branch) と呼ばれます。
名前付きブランチに属するリビジョンを親に持つリビジョンは、 以下のいずれにも当てはまらない場合、親と同じ名前付きブランチに属します。
"default" は、明示的に名前付きブランチが作られていない状態で、 生成されたリビジョンに対して割り当てられる、特別なブランチ名です。
Mercurial では、 全てのリビジョンは必ず何らかの名前付きブランチに属しますが、 特別に "default" に属しているリビジョンに関しては、 (便宜上)「名前付きブランチには属さないもの」とみなしている、 と考えてください。
なお、「名前付きブランチ」は、 必ずしも「ブランチ」状態を伴わない場合もあります。 例えば、先述した「マルチプルヘッド」での 「ヘッドを親にして新たなリビジョンを作成」する場合に、 新規リビジョンから先を「名前付きブランチ」として扱うこともできますが、 この場合、いわゆる「ブランチ」状態は発生しません。
これは、一般的な運用であれば、ブランチ元の親リビジョンに対して、 将来的に新たな子リビジョンが生成されることが想定できますので、 長期的なスパンで見た場合には「ブランチしている」と言えるでしょう。
Mercurial のマージでは、マージ対象となる2つのリビジョンが、 異なる名前付きブランチに属している場合、 どちらをマージ元/先にするかが重要となります。
2つの名前付きブランチ B_one と B_two を想定します。
作業領域の親リビジョン (= マージ先) が B_one、 マージ対象 (= マージ元) が B_two の場合、 マージによって生成されるリビジョンは B_one ブランチに属します。
この逆に、 作業領域の親リビジョンが B_two、マージ対象が B_one の場合、 マージによって生成されるリビジョンは B_two ブランチに属します。