免責事項: 私はGitを使用し、gitメーリングリストでGit開発をフォローしています。Gitにも少し貢献しています(主にgitweb)。ドキュメントからMercurialを、FreeNodeの#revctrl IRCチャネルに関する議論から一部を知っています。
この記事についてMercurialについてのヘルプを提供してくれた#mercurial IRCチャネルのすべての人々に感謝します。
概要
ここでは、PHPMarkdown / MultiMarkdown / MarkdownのMaruku拡張のような、テーブルの構文があると便利です。
- リポジトリ構造: Mercurialは、タコのマージ(3つ以上の親を持つ)や、非コミットオブジェクトのタグ付けを許可していません。
- タグ: Mercurialは
.hgtags
、リポジトリごとのタグに特別なルールが設定されたバージョン付きファイルを使用し、ローカルタグもサポートしています.hg/localtags
。in Gitタグはrefs/tags/
名前空間にある参照であり、デフォルトではフェッチ時に自動フォローされ、明示的なプッシュが必要です。
- ブランチ: Mercurialでは、基本的なワークフローは匿名のヘッドに基づいています。Gitは軽量の名前付きブランチを使用し、リモートリポジトリのブランチに続く特別な種類のブランチ(リモート追跡ブランチ)を持っています。
- リビジョンの名前と範囲: Mercurialは、リポジトリにローカルなリビジョン番号を提供し、相対的なリビジョン(チップ、つまり現在のブランチから数えます)とこのローカル番号のリビジョン範囲に基づいています。Gitはブランチの先端に関連するリビジョンを参照する方法を提供し、リビジョン範囲はトポロジーです(リビジョンのグラフに基づく)
- Mercurialは名前の変更の追跡を使用し、Gitは名前の変更の検出を使用してファイルの名前の変更を処理します
- ネットワーク: MercurialはSSHとHTTPの「スマート」プロトコル、および静的HTTPプロトコルをサポートしています。最新のGitは、SSH、HTTP、GITの「スマート」プロトコル、およびHTTP(S)の「ダム」プロトコルをサポートしています。どちらもオフライン転送用のバンドルファイルをサポートしています。
- Mercurialは拡張機能(プラグイン)と確立されたAPIを使用します。Gitにはスクリプト機能と確立されたフォーマットがあります。
MercurialとGitの違いはいくつかありますが、それらを類似させるものは他にもあります。どちらのプロジェクトもお互いからアイデアを借りています。たとえばhg bisect
、Mercurial(以前のbisect拡張機能)のgit bisect
コマンドは、Gitのコマンドgit bundle
に触発されhg bundle
ましたが、のアイデアはに触発されました。
リポジトリ構造、リビジョンの保存
Gitでは、オブジェクトデータベースに4種類のオブジェクトがあります。ファイルの内容を含むblobオブジェクト、ファイル名とファイルアクセス許可の関連部分(シンボリックリンクであるファイルの実行可能アクセス許可)を含むディレクトリ構造を格納する階層ツリーオブジェクト、作成者情報を含むコミットオブジェクト、(プロジェクトの最上位ディレクトリのツリーオブジェクトを介した)コミットによって表されるリビジョンでのリポジトリの状態のスナップショットへのポインタ、0個以上の親コミットへの参照、および他のオブジェクトを参照してできるオブジェクトのタグ付け PGP / GPGを使用して署名されている。
Gitはオブジェクトを格納する2つの方法を使用します。各オブジェクトが個別のファイルに格納されるルーズフォーマット(これらのファイルは一度だけ書き込まれ、変更されない)と、多数のオブジェクトが単一ファイルにデルタ圧縮して格納されるパックフォーマットです。操作の原子性は、新しいオブジェクトへの参照がオブジェクトを書き込んだ後に(原子的には、作成+名前変更のトリックを使用して)書き込まれるという事実によって提供されます。
Gitリポジトリーは、git gc
(ディスク・スペースを削減し、パフォーマンスを向上させるために)定期的な保守を必要としますが、現在ではGitがそれを自動的に行っています。(この方法では、リポジトリの圧縮が向上します。)
Mercurial(私が理解している限り)は、ファイルの履歴をファイルログに保存します(まとめると、名前の変更の追跡などの追加のメタデータといくつかのヘルパー情報が含まれます)。ディレクトリ構造を格納するためにマニフェストと呼ばれるフラットな構造と、コミットメッセージとゼロ、1つまたは2つの親を含むチェンジセット(リビジョン)に関する情報を格納するchangelogと呼ばれる構造を使用します。
Mercurialはトランザクションジャーナルを使用して操作の原子性を提供し、操作の失敗または中断後にファイルを切り捨ててクリーンアップします。Revlogは追加のみです。
GitとMercurialのリポジトリ構造を見ると、Gitはオブジェクトデータベース(またはコンテンツアドレス指定ファイルシステム)に似ており、Mercurialは従来の固定フィールドリレーショナルデータベースに似ていることがわかります。
相違点:
Gitでは、ツリーオブジェクトは階層構造を形成します。Mercurialのマニフェストファイルはフラット構造です。Git blobオブジェクトには、ファイルのコンテンツの1つのバージョンを格納します。Mercurialのファイルログには、1つのファイルの全履歴が保存されます(ここで名前の変更による複雑化を考慮しない場合)。つまり、GitがMercurialよりも高速である他のすべての操作(マージやプロジェクトの履歴の表示など)と、MercurialがGitよりも高速である(パッチの適用や表示など)さまざまな操作領域があります。単一ファイルの履歴)。この問題は、エンドユーザーにとって重要ではない場合があります。
Mercurialの変更ログ構造の固定レコード構造のため、Mercurialでのコミットは最大2つの親しか持つことができません。Gitのコミットは3つ以上の親を持つことができます(いわゆる「タコのマージ」)。タコのマージを一連の2つの親のマージで(理論的には)置き換えることができますが、MercurialリポジトリとGitリポジトリ間で変換するときに複雑になる可能性があります。
私の知る限り、MercurialにはGitの注釈付きタグ(タグオブジェクト)に相当するものがありません。注釈付きタグの特殊なケースはれるタグに署名し(PGP / GPG署名付き)。Mercurialの同等の機能はGpgExtensionを使用して実行できます。この拡張機能はMercurialとともに配布されています。Mercurialでは、Gitのように非コミットオブジェクトにタグを付けることはできませんが、それほど重要ではないと思います(一部のgitリポジトリでは、タグ付きblobを使用して、公開PGPキーを配布し、署名済みタグの検証に使用します)。
参照:ブランチとタグ
Gitの参照(ブランチ、リモートトラッキングブランチ、タグ)では、コミットのDAGの外側に(必要に応じて)存在します。refs/heads/
名前空間(ローカルブランチ)内の参照はコミットを指し、通常は「git commit」によって更新されます。それらはブランチの先端(ヘッド)を指しているので、そのような名前です。refs/remotes/<remotename>/
名前空間(リモート追跡ブランチ)内の参照はコミットをポイントし、リモートリポジトリ内のブランチをたどり<remotename>
、 "git fetch"または同等のものによって更新されます。refs/tags/
名前空間(tags)内の参照は通常、コミット(軽量タグ)またはタグオブジェクト(注釈付きおよび署名付きタグ)を指し、変更することを意図していません。
タグ
Mercurialでは、タグを使用してリビジョンに永続的な名前を付けることができます。タグは、無視パターンと同様に保存されます。つまり、グローバルに表示されるタグは.hgtags
、リポジトリ内のリビジョン管理されたファイルに保存されます。これには2つの影響があります。1つ目は、Mercurialはこのファイルに特別なルールを使用して、すべてのタグの現在のリストを取得し、そのようなファイルを更新する必要があります(たとえば、現在チェックアウトされていないバージョンではなく、最後にコミットされたファイルのリビジョンを読み取る)。次に、このファイルへの変更をコミットして、新しいタグを他のユーザーや他のリポジトリから見えるようにする必要があります(私が理解している限り)。
Mercurialは、に保存されている、他のユーザーには表示されない(もちろん転送できない)ローカルタグもサポートしhg/localtags
ています
In Gitのタグは、refs/tags/
名前空間に格納されている他のオブジェクト(通常はタグオブジェクトで、コミットを指す)への固定(定数)名前付き参照です。デフォルトでは、一連のリビジョンをフェッチまたはプッシュするとき、gitはフェッチまたはプッシュされるリビジョンを指すタグを自動的にフェッチまたはプッシュします。それでも、どのタグをフェッチまたはプッシュするかをある程度制御できます。
Gitは軽量タグ(直接コミットを指す)と注釈付きタグ(オプションでPGP署名を含み、次にコミットを指すタグメッセージを含むタグオブジェクトを指す)をわずかに異なる方法で処理します。たとえば、デフォルトでは、説明時に注釈付きタグのみを考慮します「git describe」を使用してコミットします。
Gitには、Mercurialのローカルタグに厳密に相当するものはありません。それにもかかわらず、gitのベストプラクティスでは、準備ができた変更をプッシュし、他の人がそこからクローンしてフェッチする、別個のパブリックベアリポジトリをセットアップすることをお勧めします。これは、プッシュしないタグ(およびブランチ)がリポジトリに対してプライベートであることを意味します。一方、ローカルタグなどではheads
、remotes
または以外の名前空間を使用することもできます。tags
local-tags
個人的な意見:私の意見では、タグはリビジョングラフの外部にあるため、リビジョングラフの外側に配置する必要があります(リビジョンのグラフへのポインタです)。タグはバージョン付けされていない必要がありますが、転送可能です。Mercurialがファイルを無視するメカニズムと同様のメカニズムを使用するという選択は、.hgtags
特別に扱う必要がある(ファイル内のツリーは転送可能ですが、通常はバージョン管理されている)か、ローカルのみのタグがある(.hg/localtags
バージョン管理されていない、ただし、譲渡できません)。
枝
Gitでは、ローカルブランチ(ブランチチップ、またはブランチヘッド)はコミットへの名前付き参照であり、新しいコミットを増やすことができます。ブランチは、アクティブな開発ライン、つまりブランチの先端から到達可能なすべてのコミットを意味することもあります。ローカルブランチはrefs/heads/
名前空間に存在するため、たとえば「master」ブランチの完全修飾名は「refs / heads / master」です。
Gitの現在のブランチ(チェックアウトされたブランチ、および新しいコミットが行われるブランチ)は、HEAD参照によって参照されるブランチです。シンボリック参照ではなく、コミットを直接指すHEADを持つことができます。名前のない匿名のブランチにいるこの状況は、デタッチされたHEADと呼ばれます(「gitブランチ」は、「(ブランチなし)」にいることを示しています)。
Mercurialには匿名のブランチ(ブランチヘッド)があり、ブックマーク拡張機能(ブックマーク拡張機能を介して)を使用できます。そのようなブックマークブランチは純粋にローカルであり、それらの名前は(バージョン1.6まで)Mercurialを使用して転送できませんでした。rsyncまたはscpを使用して、.hg/bookmarks
ファイルをリモートリポジトリにコピーできます。を使用hg id -r <bookmark> <url>
して、ブックマークの現在のヒントのリビジョンIDを取得することもできます。
1.6以降、ブックマークはプッシュ/プルできます。BookmarksExtensionのページには、上のセクションがあるリモートリポジトリで作業を。Mercurialではブックマーク名がグローバルであるという違いがありますが、Gitでの「リモート」の定義では、リモートリポジトリ内の名前からローカルのリモート追跡ブランチの名前へのブランチ名のマッピングも記述されています。たとえば、refs/heads/*:refs/remotes/origin/*
マッピングとは、リモートリポジトリの 'origin / master'リモート追跡ブランチ( 'refs / remotes / origin / master')の 'master'ブランチ( 'refs / heads / master')の状態を見つけることができることを意味します。
Mercurialは、いわゆる名前付きブランチとも呼ばれ、ブランチ名は(チェンジセット内の)コミットに埋め込まれます。そのような名前はグローバルです(フェッチ時に転送されます)。これらのブランチ名は、変更セットのメタデータの一部として永続的に記録されます。最新のMercurialでは、「名前付きブランチ」を閉じて、ブランチ名の記録を停止できます。このメカニズムでは、ブランチのヒントがその場で計算されます。
Mercurialの「名前付きブランチ」は、私の意見では、代わりにコミットラベルと呼ばれるべきです。「名前付きブランチ」には複数のヒント(複数の子なしのコミット)があり、リビジョンのグラフのいくつかのばらばらな部分で構成される場合もあります。
GitにはこれらのMercurialの「埋め込みブランチ」に相当するものはありません。さらに、Gitの哲学は、ブランチにコミットが含まれていると言っても、コミットがブランチに属していることを意味するわけではありません。
Mercurialのドキュメントでは、少なくとも長期的なブランチ(リポジトリワークフローごとの単一のブランチ)、つまり複製によるブランチでは、別個のクローン(別個のリポジトリ)を使用することを提案しています。
プッシュのブランチ
Mercurialはデフォルトですべての頭を押し上げます。単一のブランチ(単一のヘッド)をプッシュする場合は、プッシュするブランチのチップリビジョンを指定する必要があります。ブランチチップは、リビジョン番号(リポジトリに対してローカル)、リビジョン識別子、ブックマーク名(リポジトリに対してローカル、転送されない)、または埋め込まれたブランチ名(名前付きブランチ)で指定できます。
私が理解している限り、Mercurial用語で「名前付きブランチ」にあるとマークされたコミットを含むリビジョンの範囲をプッシュすると、プッシュするリポジトリにこの「名前付きブランチ」ができます。これは、そのような埋め込まれたブランチ(「名前付きブランチ」)の名前がグローバルであることを意味します(特定のリポジトリ/プロジェクトのクローンに関して)。
デフォルトでは(push.default
設定変数に従います) "git push"または "git push < remote >" Gitは一致するブランチをプッシュします。つまり、リモートリポジトリに同等のものがすでに存在するローカルブランチのみをプッシュします。--all
git-push( "git push --all")のオプションを使用してすべてのブランチをプッシュできます。「git push < リモート > < ブランチ > "を使用して特定の単一のブランチをプッシュできます。また、「git push < 現在のブランチをプッシュするリモート >ヘッド」。
上記のすべては、remote.<remotename>.push
設定変数を介してプッシュするブランチがGitに設定されていないことを前提としています。
フェッチのブランチ
注:ここでは、Gitの用語を使用しています。「フェッチ」とは、変更をローカル作業と統合せずに、リモートリポジトリから変更をダウンロードすることを意味します。これが「git fetch
」と「hg pull
」の機能です。
私がそれを正しく理解している場合、Mercurialはデフォルトでリモートリポジトリからすべてのヘッドをフェッチしますが、「hg pull --rev <rev> <url>
」または「hg pull <url>#<rev>
」を介してフェッチするブランチを指定して単一のブランチを取得できます。リビジョン識別子、「名前付きブランチ」名(変更ログに埋め込まれたブランチ)、またはブックマーク名を使用して<rev>を指定できます。ただし、ブックマーク名は(少なくとも現在のところ)転送されません。取得したすべての「名前付きブランチ」リビジョンは転送されます。"hg pull"は匿名で名前のないヘッドとしてフェッチしたブランチのヒントを保存します。
デフォルトではGitで(「git clone」によって作成された「origin」リモート、および「git remote add」を使用して作成されたリモートの場合)「git fetch
」(または「git fetch <remote>
」)は、リモートリポジトリから(ネームスペースから)すべてのブランチを取得refs/heads/
し、それらをrefs/remotes/
名前空間。これは、たとえば、リモート 'origin'にある 'master'(フルネーム: 'refs / heads / master')という名前のブランチが 'origin / master' リモート追跡ブランチ(フルネーム: 'refs / )として保存(保存)されることを意味しますremotes / origin / master ')。
あなたは取り出すことができる単一の分岐を使用してGitリポジトリにgit fetch <remote> <branch>
- GitはMercurialの無名の頭に似たものであるFETCH_HEADで要求されたブランチ(複数可)、格納します。
これらは、強力なrefspec Git構文のデフォルトの例にすぎません。refspecを使用すると、フェッチするブランチとそれらを格納する場所を指定または構成できます。たとえば、デフォルトの「すべてのブランチをフェッチする」ケースは「+ refs / heads / *:refs / remotes / origin / *」ワイルドカードrefspecで表され、「単一ブランチをフェッチする」は「refs / heads / <branch>:」の省略形です。 。refspecは、リモートリポジトリのブランチ(ref)の名前をローカルのrefs名にマップするために使用されます。しかし、Gitを効果的に使用できるようにするために、refspecについて(多くのこと)を知る必要はありません(主に「git remote」コマンドのおかげです)。
個人的な意見:個人的には、Mercurialの「名前付きブランチ」(変更セットのメタデータにブランチ名が埋め込まれている)は、特に分散バージョン管理システムの場合、グローバルネームスペースの設計に誤りがあると思います。たとえば、アリスとボブの両方のリポジトリに「for-joe」という名前の付いた「名前付きブランチ」があり、共通のブランチがない場合を考えてみましょう。ただし、ジョーのリポジトリでは、これらの2つのブランチは1つのブランチとして誤って扱われます。したがって、ブランチ名の衝突を防ぐための慣例が何とかできました。これはGitでは問題ではありません。Joeのリポジトリでは、Aliceからの「for-joe」ブランチは「alice / for-joe」になり、Bobからは「bob / for-joe」になります。
Mercurialの「ブックマークブランチ」には現在、コア内配布メカニズムがありません。
相違点:
この領域は、James WoodyattとSteve Loshが回答で述べたように、MercurialとGitの主な相違点の1つです。Mercurialはデフォルトで匿名の軽量コードラインを使用します。このコードラインはその用語では「ヘッド」と呼ばれます。Gitは、軽量の名前付きブランチを使用し、インジェクティブマッピングを使用して、リモートリポジトリ内のブランチの名前をリモート追跡ブランチの名前にマップします。Gitはブランチに名前を付けるよう強制します(まあ、名前のない単一のブランチを除いて、切り離されたHEADと呼ばれる状況です)が、これはトピックブランチワークフローなどのブランチの多いワークフロー、つまり単一のリポジトリパラダイムに複数のブランチがある場合に適しています。
リビジョンの命名
Gitには、リビジョンに名前を付ける方法がたくさんあります(たとえば、git rev-parseマンページで説明されています)。
- 完全なSHA1オブジェクト名(40バイトの16進数ストリング)、またはリポジトリー内で固有のものなどのサブストリング
- シンボリック参照名。例: 'master'( 'master'ブランチを参照)、または 'v1.5.0'(タグを参照)、または 'origin / next'(リモート追跡ブランチを参照)
^
リビジョンパラメータのサフィックスは、コミットオブジェクトの最初の親^n
、マージコミットのn番目の親を意味します。~n
リビジョンパラメータのサフィックスは、最初の親の直線でのコミットのn番目の祖先を意味します。これらのサフィックスを組み合わせて、シンボリック参照からのパスに続くリビジョン指定子を形成できます(例: 'pu〜3 ^ 2〜3')。
- 「git describe」の出力、つまり最も近いタグ。オプションでダッシュといくつかのコミットが続き、その後にダッシュ、「g」、および省略されたオブジェクト名が続きます。たとえば、「v1.6.5.1-75- g5bf8097 '。
ここでは言及していませんが、reflogを含むリビジョン指定子もあります。Gitでは、コミット、タグ、ツリー、ブロブの各オブジェクトにSHA-1識別子があります。指定されたリビジョンのツリー(ディレクトリ)またはブロブ(ファイルの内容)を参照するために、たとえば 'next:Documentation'または 'next:README'のような特別な構文があります。
Mercurialには、チェンジセットに名前を付ける方法も多数あります(たとえば、hgマンページで説明されています)。
- プレーン整数はリビジョン番号として扱われます。リビジョン番号は特定のリポジトリに対してローカルであることを覚えておく必要があります。他のリポジトリでは異なる場合があります。
- 負の整数は、チップからの連続したオフセットとして扱われ、-1はチップを示し、-2はチップの前のリビジョンを示します。また、リポジトリに対してローカルです。
- 一意のリビジョン識別子(40桁の16進文字列)またはその一意のプレフィックス。
- タグ名(特定のリビジョンに関連付けられたシンボル名)、またはブックマーク名(拡張子:リポジトリにローカルな特定のヘッドに関連付けられたシンボル名)、または「名前付きブランチ」(コミットラベル。「名前付きブランチ」で指定されたリビジョンは特定のコミットラベルを持つすべてのコミットのティップ(子なしコミット)。そのようなティップが複数ある場合は最大のリビジョン番号が付いています)
- 予約名「tip」は、常に最新のリビジョンを識別する特別なタグです。
- 予約名「null」は、nullリビジョンを示します。
- 予約名「。」作業ディレクトリの親を示します。
違い
上記のリストを比較するとわかるように、Mercurialはリポジトリにローカルなリビジョン番号を提供していますが、Gitは提供していません。一方、Mercurialは 'tip'(現在のブランチ)からの相対オフセットのみを提供します。これはリポジトリに対してローカルです(少なくともParentrevspecExtensionなし)。Gitでは、任意のチップからのコミットを指定できます。
最新のリビジョンはGitではHEAD、Mercurialでは「tip」という名前です。Gitにはnullリビジョンはありません。MercurialとGitは両方とも多くのルートを持つことができます(複数の親なしのコミットを持つ可能性があります。これは通常、以前は別々のプロジェクトが参加した結果です)。
参照: Elijah's Blog(newren's)のさまざまな種類のリビジョン指定子の記事。
個人的な意見:リビジョン番号は過大評価されていると思います(少なくとも分散型開発および/または非線形/分岐の履歴に対して)。まず、分散バージョン管理システムの場合は、リポジトリに対してローカルであるか、一部のリポジトリを特別な方法で中央の番号付け機関として扱う必要があります。第2に、より長い履歴のある大きなプロジェクトは、5桁の範囲のリビジョン数を持つことができるため、6〜7文字のリビジョンIDに比べてわずかな利点しかなく、リビジョンが部分的にしか順序付けられていないのに厳密な順序付けを意味します(つまり、リビジョンnとn + 1は親と子である必要はありません)。
リビジョン範囲
Gitのリビジョン範囲はトポロジーです。一般的に見られるA..B
構文は、線形履歴の場合、リビジョン範囲がAから始まり(Aを除く)、Bで終わる(つまり、範囲が下から開いている)^A B
ことを意味し、の省略形(「構文糖」)です。これは、A..B
AがBの祖先でなくても、範囲の動作が完全に予測可能(かつ非常に有用)であるA..B
ことを意味します。つまり、AとBの共通の祖先からのリビジョンの範囲(マージベース)を意味します。 )リビジョンBに
Mercurialのリビジョン範囲は、リビジョン番号の範囲に基づいています。範囲はA:B
構文を使用して指定され、Gitの範囲とは逆に、閉じた間隔として機能します。また、範囲B:Aは逆順の範囲A:Bです。これは、Gitの場合とは異なります(ただし、A...B
構文に関する以下の注を参照)。しかし、そのような単純さには代償が伴います。リビジョン範囲A:Bは、AがBの祖先であるか、その逆の場合、つまり線形履歴の場合にのみ意味があります。それ以外の場合(私はそう思います)範囲は予測不可能であり、結果はリポジトリに対してローカルです(リビジョン番号はリポジトリに対してローカルであるため)。
これはMercurial 1.6で修正されました。これには新しいトポロジリビジョン範囲があり、 'A..B'(または 'A :: B')はXの子孫でありYの祖先でもある変更セットのセットとして理解されます。これは、Gitの '--ancestry-path A..B'に相当します。
GitにはA...B
、リビジョンの対称的な違いに関する表記もあります。つまりA B --not $(git merge-base A B)
、AまたはBから到達可能なすべてのコミットを意味しますが、両方から到達可能なすべてのコミット(共通の祖先から到達可能なコミット)を除外します。
名前を変更
Mercurialは、名前の変更の追跡を使用してファイルの名前の変更を処理します。つまり、ファイルの名前が変更されたという情報は、コミット時に保存されます。Mercurialの中で、この情報は「強化デフ」の形式で保存されてfilelog(ファイルrevlog)メタデータ。この結果、hg rename
/ hg mv
... を使用する必要があります。または、hg addremove
類似性に基づく名前の変更の検出を実行することを忘れないでください。
Gitは、ファイル名の変更を処理するために名前変更検出を使用するという点で、バージョン管理システム間でユニークです。これは、ファイルの名前が変更されたという事実が必要なときに検出されることを意味します:マージを実行するとき、または差分を表示するとき(要求/構成されている場合)。これには、名前変更検出アルゴリズムを改善できるという利点があり、コミット時にフリーズしません。
GitとMercurialはどちらも--follow
、単一のファイルの履歴を表示するときに、名前の変更に従うオプションを使用する必要があります。git blame
/ 内のファイルの行ごとの履歴を表示する場合、どちらも名前変更に従うことができますhg annotate
。
Gitではgit blame
、コードの移動が健全なファイル名変更の一部ではない場合でも、コマンドはコードの移動を追跡でき、コードを1つのファイルから別のファイルに移動(またはコピー)することもできます。 私の知る限り、この機能はGit固有のものです(執筆時点では2009年10月)。
ネットワークプロトコル
MercurialとGitはどちらも、同じファイルシステム上のリポジトリからのフェッチとそこへのプッシュをサポートしています。リポジトリURLは、リポジトリへのファイルシステムパスにすぎません。どちらも、バンドルファイルからのフェッチをサポートしています。
Mercurialは、SSHおよびHTTPプロトコルを介したフェッチおよびプッシュをサポートしています。SSHの場合は、宛先マシンにアクセス可能なシェルアカウントと、インストール/利用可能なhgのコピーが必要です。HTTPアクセスのhg-serve
場合、またはMercurial CGIスクリプトを実行する必要があり、サーバーマシンにMercurialをインストールする必要があります。
Gitは、リモートリポジトリへのアクセスに使用される2種類のプロトコルをサポートしています。
- SSHおよびカスタムgit://プロトコル(による
git-daemon
)経由のアクセスを含む「スマート」プロトコルでは、サーバーにgitがインストールされている必要があります。これらのプロトコルでの交換は、共通のオブジェクトについてクライアントとサーバーがネゴシエートし、パックファイルを生成して送信することで構成されます。最新のGitには、「スマート」HTTPプロトコルのサポートが含まれています。
- HTTPおよびFTP(フェッチのみ)およびHTTPS(WebDAVを介したプッシュ用)を含む「ダム」プロトコルは、サーバーにgitをインストールする必要はありませんが、
git update-server-info
(通常、フックから実行される)によって生成された追加情報をリポジトリに含める必要があります。)。交換は、クライアントがコミットチェーンをたどり、ルーズオブジェクトとパックファイルを必要に応じてダウンロードすることで構成されます。欠点は、厳密に必要なダウンロードよりも多くダウンロードすることです(たとえば、単一のパックファイルしかないコーナーケースでは、いくつかのリビジョンしかフェッチしない場合でも全体がダウンロードされます)、終了するために多くの接続が必要になる場合があります。
拡張:スクリプト機能と拡張機能(プラグイン)
MercurialはPythonで実装されており、パフォーマンス向上のためにいくつかのコアコードがCで記述されています。追加機能を追加する方法として、拡張機能(プラグイン)を作成するためのAPIを提供します。「ブックマークブランチ」や署名リビジョンなどの一部の機能は、Mercurialとともに配布される拡張機能で提供されるため、有効にする必要があります。
GitはC、Perl、シェルスクリプトで実装されています。Gitには、スクリプトでの使用に適した多くの低レベルコマンド(plumb)が用意されています。新しい機能を導入する通常の方法は、それをPerlまたはシェルスクリプトとして記述し、ユーザーインターフェイスが安定したときに、パフォーマンス、移植性、およびシェルスクリプトの場合はコーナーケースを回避するためにCで書き換えます(この手順は組み込みと呼ばれます)。
Gitは、[リポジトリ]フォーマットと[ネットワーク]プロトコルに依存して構築されています。言語バインディングの代わりに、他の言語でのGitの(部分的または完全な)再実装があります(これらの一部は部分的に再実装され、部分的にgitコマンドのラッパーです):JGit(Java、EGit、Eclipse Gitプラグインで使用)、Grit(Ruby) 、Dulwich(Python)、git#(C#)。
TL; DR