GitとMercurial-比較と対比


520

しばらくの間、私は個人的なプロジェクトにsubversionを使用しています。

GitやMercurial、そしてDVCS全般について素晴らしいことをどんどん聞いています。

DVCS全体を試してみたいのですが、どちらのオプションにも慣れていません。

MercurialとGitの違いは何ですか?

注:私は、どれが「最高」であるか、あるいはどれを最初に使用する必要があるかを見つけることを試みていません。実装と哲学の点でどのように異なるかを知りたいので、主にそれらが類似している主要な領域とそれらが異なる主要な領域を探しています。



回答:


451

免責事項: 私は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のベストプラクティスでは、準備ができた変更をプッシュし、他の人がそこからクローンしてフェッチする、別個のパブリックベアリポジトリをセットアップすることをお勧めします。これは、プッシュしないタグ(およびブランチ)がリポジトリに対してプライベートであることを意味します。一方、ローカルタグなどではheadsremotesまたは以外の名前空間を使用することもできます。tagslocal-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は一致するブランチをプッシュします。つまり、リモートリポジトリに同等のものがすでに存在するローカルブランチのみをプッシュします。--allgit-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 WoodyattSteve 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..BAが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はCPerlシェルスクリプトで実装されています。Gitには、スクリプトでの使用に適した多くの低レベルコマンド(plumb)が用意されています。新しい機能を導入する通常の方法は、それをPerlまたはシェルスクリプトとして記述し、ユーザーインターフェイスが安定したときに、パフォーマンス、移植性、およびシェルスクリプトの場合はコーナーケースを回避するためにCで書き換えます(この手順は組み込みと呼ばれます)。

Gitは、[リポジトリ]フォーマットと[ネットワーク]プロトコルに依存して構築されています。言語バインディングの代わりに、他の言語でのGitの(部分的または完全な)再実装があります(これらの一部は部分的に再実装され、部分的にgitコマンドのラッパーです):JGit(Java、EGit、Eclipse Gitプラグインで使用)、Grit(Ruby) 、Dulwich(Python)、git#(C#)。


TL; DR


32
追加できるのは、hgが履歴の書き換えを阻止するために非常に一生懸命に試行することです(これは拡張機能:mq、histedit、rebaseでのみ実行できます)が、gitはそのままで(コミュニティーの一部のように見えます)さえそれを奨励する)。
tonfa

80
「書き直しの歴史」は不必要にネガティブな響きだと思います。どのような私は gitのに奨励することは、人々は、彼らが発行する歴史を考慮することです。他の人々はその歴史を消費する必要があります。誰も(あなたでさえ)あなたの "おっと、ファイルを忘れた"コミットのすべてに興味を持っていません。また、新機能の開発中にアップストリームブランチを追跡しているときに行った一連のインバウンドマージを気にする人もいません。この種のものは、履歴(および関連ツール)を理解することをはるかに困難にし、価値を提供しません。
ダスティン

5
@Jakub:名前付きブランチはgitには存在しないものです。これは単にcset記述のフィールドです(これは履歴の一部であるため、ハッシュを変更しない限り不変です)。gitブランチのようなものはブックマーク(「名前付きヘッド」)ですが、現在はリモート転送できません(プルするときにリモートブックマークをインポートしません)。 stevelosh.com/blog/entry/2009/8/30/…非常によく説明しています。
tonfa

28
「Mercurialは元々、リポジトリワークフローごとに1つのブランチしかサポートしていませんでした。」ええと、違います。Mercurialは元々名前付きブランチをサポートしていませんでしたが、1つのリポジトリで、心臓の望むだけの数の匿名ブランチを常に持つことができました。それをgitと比較すると、匿名の分岐が非常に困難になります。あなたはかなり持っているあなたが何かを成し遂げるにしたい場合は、すべての小さな枝の名前を考えるように(そしてあなたの仕事のガベージコレクションを避けます)。
スティーブロス

17
@SteveLosh:Mercurialに匿名のブランチをたくさん持つことは良いことだと思うかもしれませんが、私には恐ろしいようです。それらをどのように区別するのですか?また、Gitでブランチに名前を付けるのは非常に難しいと思いますが、ブランチを作成する目的がある場合は、既成の名前を付けます。目的がない場合は、分岐しないでください。ここでMercurialがどのようなメリットをもたらすかはわかりません。痛みと混乱だけが見える。
iconoclast、2012

57

これらの2つのビデオをわいせつにすることで、これらのシステムの類似点や相違点を理解できると思います。

Git上のLinus Torvalds(http://www.youtube.com/watch?v=4XpnKHJAok8
Mercurial上のBryan O'Sullivan(http://www.youtube.com/watch?v=JExtkqzEoHY

どちらもデザインは非常に似ていますが、実装方法が大きく異なります。

Mercurialを使用しています。私がGitを理解している限り、gitの主な違いの1つは、ファイル自体ではなくファイルの内容を追跡することです。Linusによれば、あるファイルから別のファイルに関数を移動すると、Gitは移動全体でその単一の関数の履歴を教えてくれます。

彼らはまた、gitはHTTPより遅いと言っていますが、独自のネットワークプロトコルとサーバーを備えています。

GitはMercurialよりもSVNシッククライアントとして機能します。SVNサーバーに対してプルおよびプッシュできます。この機能はMercurialでまだ開発中です

MercurialとGitはどちらも非常に優れたWebホスティングソリューション(BitBucketとGitHub)を利用できますが、Google CodeはMercurialのみをサポートしています。ちなみに、MercurialとGitの非常に詳細な比較があり、どちらをサポートするかを決定しました(http://code.google.com/p/support/wiki/DVCSAnalysis)。良い情報がたくさんあります。


8
そのGoogleコードページのすべてのコメントを読むことをお勧めします。情報は多少偏っていると感じ、私の経験とうまく一致しません。私はhgが好きで、1年ほど広範に使用しました。私は今、ほぼ排他的にgitを使用しています。gitが簡単になり、hgがほとんど不可能になることを実現するために必要なことがいくつかあります(「複雑化」によってこれを呼ぶ人もいますが)。基本的なgitはベースのhgと同じくらい簡単です。
ダスティン

11
ダスティン、「git easy、hg not much」のケースをいくつか挙げてください。
グレッグリンド

1
@knittlいいえ、ありません。gitにはスマートなhttpプロトコルがないため(ほとんどのGoogleフロントエンドはhttpベースです)、デプロイするのが面倒なためです。
tonfa

2
@tonfa:GitのスマートHTTPプロトコルは現在開発中です(例:gitメーリングリストにパッチがあり、それらは 'pu' = git.gitリポジトリの提案された更新ブランチにあります)。
JakubNarębski、2009年

4
現在、Google CodeはGitもサポートしています。
AndrejKirejeŭ2012

30

Mercurialの分岐モデルに関するブログエントリを少し前に書いて、gitの分岐モデルとの比較を含めました。多分あなたはそれを面白いと思うでしょう:http : //stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/


@Steve Losh:私はこのブログエントリ(名前のないブランチ(別名detached HEAD)について、およびgit-fetchが1つではなくすべてのブランチをフェッチすること)についてコメントしたかったのですが、500サーバーエラーが発生しました。
JakubNarębski、2009年

1
@JakubNarębski問題はあなたの名前の非ASCII文字にあると思います。私は別のサイトで同じ問題に遭遇したと確信していますが、Python AskimetバインディングがUnicodeで窒息していることがわかりました。見てみます。
スティーブロス

@Steve Losh:情報をありがとう、私の名前を「unidecoding」した後、コメントを投稿することができました。Mercurialでの分岐の非常に優れた説明(ただし、それでも劣っているように思います
;

@SteveLosh私はあなたがこの答えを水銀のより完全なレビューに拡張することをお勧めします。現在、トップの答えは残念ながらほとんどがgitの広告です。その作者はmercurialを広範囲に使用しておらず、効果的な使用方法を理解していないためです。いわば、水銀の観点を提供する別の答えがいいでしょう。
ウォーレンデュー

25

私はどちらもかなり頻繁に使用しています。主な機能の違いは、GitとMercurialの名前がリポジトリ内で分岐する方法にあります。Mercurialでは、ブランチ名が複製され、チェンジセットとともにプルされます。Mercurialの新しいブランチに変更を追加し、別のリポジトリにプッシュすると、ブランチ名も同時にプッシュされます。したがって、ブランチ名はMercurialでは多かれ少なかれグローバルであり、ローカルのみの軽量名を付けるには、ブックマーク拡張機能を使用する必要があります(必要な場合は、Mercurialはデフォルトで匿名軽量コードラインを使用します)。 「ヘッド」と呼ばれます)。Gitでは、ブランチ名とリモートブランチへの単射マッピングはローカルに保存され、明示的に管理する必要があります。つまり、その方法を知っている必要があります。

他の人がここで気づくように、たくさんの小さな違いがたくさんあります。枝のあるものは大きな差別化要因です。


2
Mercurialの4種類のブランチに関する詳しい説明については、この投稿も参照してください。stevelosh.com/ blog
Martin Geisler


11

Mercurialはほぼ完全にpythonで書かれています。GitのコアはCで記述され(Mercurialのコアより高速である必要があります)、sh、perl、tclで記述されたツールであり、標準のGNU utilsを使用します。したがって、これらすべてのユーティリティとインタープリターを、それらを含まないシステム(Windowsなど)に持ってくる必要があります。

どちらのサポートもSVNで機能しますが、AFAIKのsvnサポートはWindowsのgitでは壊れています(たぶん私は不運な/不運なだけかもしれません)。gitとMercurialの相互運用を可能にする拡張機能もあります。

MercurialはVisual Studioとの統合が優れています。前回チェックしたところ、Gitのプラグインは機能していましたが、非常に遅くなりました。

基本的なコマンドセットは非常によく似ています(init、clone、add、status、commit、push、pullなど)。したがって、基本的なワークフローは同じです。また、両方にTortoiseSVNのようなクライアントがあります。

Mercurialの拡張機能はpython(驚くべきことではありません)で記述でき、gitの拡張機能は任意の実行形式(実行可能バイナリ、シェルスクリプトなど)で記述できます。一部の拡張機能は、のように非常に強力git bisectです。


9
MercurialコアはCでも書かれています(ただし、おそらくgitよりも小さいコアです)。
tonfa

1
私はWindowsでgit-svnを問題なく使用しています。これはCygwinを使用しています(Windowsでgitを使用する唯一の正しい方法は、私に尋ねた場合)。msysgitについて話すことができません。
ダン成形

@Dan Moulding:はい、msysgitで問題が発生しました。たぶん、cygwinへの移植を試してみる必要があるかもしれません(以前にcygwinを使用した経験がなかったため、回避しました)。アドバイスをありがとう!
elder_george 2009年

ユーザーデータを格納するためのレジストリへのcygwinの侵入は個人的に嫌いです。USBキーで実行できる速度よりも速く実行したい場合に備えて、USBキーを使用せずにローカルのc:\ドライブのコピーを同期させるのはPITAです。:-/
クリスK

1
上記のVisual Studio用Gitプラグインを使用していますが、現在のバージョンのパフォーマンスは良好です。コマンドラインツールを使用して作業を行うため、大規模なプロジェクトでパフォーマンスが大幅に低下することはないと思います。
スチュアートエリス

11

優れたWindowsサポートが必要な場合は、Mercurialを使用することをお勧めします。TortoiseHg(Windowsエクスプローラプラグイン)は、かなり複雑なツールに対して、使いやすいグラフィカルインターフェイスを提供します。ここに示すように、Visual Studioプラグインも用意されています。ただし、前回試したところ、WindowsではSVNインターフェイスがうまく機能しませんでした。

コマンドラインインターフェイスを気にしない場合は、Gitをお勧めします。技術的な理由ではなく、戦略的な理由によるものです。gitの採用率ははるかに高いです。cvs / svnからMercurialに切り替えられている有名なオープンソースプロジェクトの数と、Gitに切り替えられているプロジェクトの数を確認してください。Mercurialホスティングと比較して、gitサポートで見つけられるコード/プロジェクトホスティングプロバイダーの数をご覧ください。


コマンドラインを使用したくない場合は、TortoiseGitもあります。(ただし、msysgitをインストールする必要があります。)
ベンジェームズ

2
私たちの会社は、Windowsでの優れたサポートが理由でgitを選択することになりました。GitExtensionsをチェックしてください。現在は寄稿者なので偏見がありますが、使い始めたときはそうではありませんでした。
Jacob Stanley

11

Mercurialの方がずっと簡単に読めた後(インターネットコミュニティの意見としてはまだそうですが)、GitとMercurialを使い始めたとき、Gitは比較的簡単に適応できるようになりました(私は始めました) MercurialとTortoiseHgを併用した場合)コマンドラインから作業する場合、主にgitコマンドは私に応じて適切に名前が付けられ、数が少ないためです。Mercurialは異なるコマンドを実行するコマンドごとに異なる名前を付けていますが、Gitコマンドは状況に応じて多目的にすることができます(たとえば、checkout)。当時Gitはより困難でしたが、今ではその違いはほとんどありません。YMMV .. TortoiseHgのような優れたGUIクライアントを使用すると、Mercurialでの作業がはるかに簡単になり、少し混乱するコマンドを覚える必要がなくなりました。私はどのように変化し、同じアクションのためのすべてのコマンドの詳細につもりはないが、ここでは2つの包括的リストである:1はMercurialの自分のサイトからwikivsから2番目

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Gitはコミットされたファイルのすべてのバージョンのレコードを内部で保存しますが、Hgは、フットプリントが小さいチェンジセットのみを保存します。GitはHgと比較して履歴の変更を容易にしますが、それでも嫌いな、または好きな機能です。前者はHg、後者はGitが好きです。

Hgで見逃しているのは、Gitのサブモジュール機能です。Hgにはサブリポジトリがありますが、それはGitサブモジュールではありません。

2つの周りのエコシステムも1つの選択に影響を与える可能性があります:Gitはより人気がある必要があります(しかし、それは些細なことです)、GitはGitHubを持っていますが、MercurialはBitBucketを持っています、MercurialはTortoiseHgを持っています。

それぞれに長所と短所があり、どちらも失うことはありません。


8

Scott Chaconの投稿をしばらく前にチェックしてください。

gitは「より複雑」であるとの評判があると思いますが、私の経験では、必要以上に複雑ではありません。IMO、gitモデルは理解しやすい方法です(タグにはコミット(および0個以上の親コミットへのポインター)にはツリーが含まれ、ブロブやその他のツリーが含まれます...完了)。

gitがmercurialほど混乱しないのは、私の経験だけではありません。この件についてスコットチャコンからのこのブログ投稿をもう一度読むことをお勧めします。


1
Mercurialモデルは実際にはほとんど同じです:changelogはマニフェストポイントをファイルリビジョン/ブロブにポイントします...完了。ディスク上のフォーマットを比較する場合、おそらくhgの単純なrevlogフォーマットよりも説明が難しいpacksファイルを考慮に入れていません。
tonfa

まあ、その簡略化されたモデルはhgで実際にかなり不格好なタグ付けを無視します(ただし、デフォルトではタグオブジェクトを作成しないため、gitタグは少しわかりにくいと主張しています)。ディスク上のフォーマットは、多くのファイル名の履歴を持つ両方のプロジェクトにとって特に高価でした。
ダスティン

1
私はモデルがタグ付けを無視するとは思わない:タグ付けはMercurialでは取るに足らないことです-ご存知のように、それはSHA-1ハッシュに名前を付ける単なるファイルです。システム内でタグがどのように流れるかについては当て推量はありません。タグはプッシュとプルに沿って移動します。タグの競合がある場合、それを解決するのも簡単です。他の競合と同じように解決します。結局のところ、それはテキストファイルの1行にすぎません。このモデルのシンプルさは非常に優れた機能だと思います。
マーティンガイスラー、

ダスティン:ええ、.hgtagsリビジョン1.0をチェックアウトしたときに1.0タグが表示されていないことで、ユーザーはしばしば混乱します。ただし、内部を見る必要はなく、すべてのタグがリストされ.hgtagshg tagsいることがわかります。さらに、この動作は、バージョン管理されたファイルにタグを保存することによる単純な結果です。この場合も、モデルは把握しやすく、非常に予測可能です。
Martin Geisler、

1
Martin Geisler Mercurialのタグのルールはトランスポートにバージョン管理されたファイルを使用し、タグを非バージョン化するための特別なルールのレイヤーを使用するために必要であるため、簡単に理解できないと主張します。
JakubNarębski、2009年

5

現在の仕事では1年弱Gitを使用しており、それ以前は前職でMercurialを1年弱使用していました。ユーザーの視点で評価していきます。

まず、どちらも分散バージョン管理システムです。分散バージョン管理システムは、従来のバージョン管理システムからの考え方の変更を必要としますが、実際に理解すれば、多くの点で多くの点で機能します。このため、SubversionやPerforceなどよりもGitとMercurialの両方がはるかに優れていると考えています。分散バージョン管理システムと従来のバージョン管理システムの違いは、GitとMercurialの違いよりもはるかに大きくなっています。

ただし、GitとMercurialの間には、それぞれがユースケースの独自のサブセットにより適しているという大きな違いもあります。

Mercurialの方が学習が簡単です。Mercurialを数週間使用した後、ドキュメントやメモを参照する必要がほとんどないところまでたどり着きました。1年間使用した後でも、Gitでノートを定期的に参照する必要があります。Gitはかなり複雑です。

これは、Mercurialのほうが単純なためです。Mercurialで手動でブランチする必要はほとんどありません。Mercurialは、必要に応じて匿名ブランチを自動的に作成します。Mercurialの命名法はより直感的です。Gitの場合のように、「フェッチ」と「プル」の違いを気にする必要はありません。Mercurialは少しバグが少ないです。GitとMercurialの両方でプラットフォーム間でプロジェクトをプッシュするときに問題を引き起こすファイル名の大文字と小文字の区別の問題があります。これは少し前にMercurialで修正されましたが、最後にチェックしたGitでは修正されていませんでした。Mercurialにファイル名の変更を通知できます。Gitの場合、名前の変更が自動的に検出されない場合-私の経験では命中または失敗の命題-名前の変更はまったく追跡できません。

ただし、Gitがさらに複雑になるもう1つの理由は、Gitの多くが追加の機能とパワーをサポートするために必要であることです。はい、Gitで分岐を処理することはより複雑ですが、一方、分岐を取得すると、Mercurialでは事実上不可能である分岐を使用して作業を行うことはそれほど難しくありません。ブランチのリベースはこれらの1つです。ブランチを移動すると、そのベースが、ブランチしたときのトランクの状態ではなく、トランクの状態になります。これにより、同じコードベースで作業している人が多い場合に、バージョン履歴が大幅に簡素化されます。これは、トランクへのプッシュのそれぞれが絡み合うのではなく、シーケンシャルに見えるようにすることができるためです。同様に、ブランチ上の複数のコミットを1つのコミットにまとめる方がはるかに簡単です。

最終的には、MercurialとGitのどちらを選択するかは、バージョン管理プロジェクトの規模に依存するはずであり、同時に作業している人の数で測定されると思います。たとえば、単一のモノリシックWebアプリケーションで作業している12人以上のグループがある場合、Gitのより強力なブランチ管理ツールを使用すると、プロジェクトに非常によく適合します。一方、チームが異種分散システムを開発していて、一度に1つまたは2つの開発者のみが1つのコンポーネントに取り組んでいる場合、各コンポーネントプロジェクトにMercurialリポジトリを使用すると、開発をより少ない時間でよりスムーズに進めることができます。リポジトリ管理のオーバーヘッド。

結論:大きなチームが1つの巨大なアプリケーションを開発している場合は、Gitを使用します。個々のアプリケーションが小規模で、そのようなアプリケーションのサイズではなく数に基づいている場合は、Mercurialを使用してください。


4

DVCS自体とはまったく無関係な1つの違い:

GitはC開発者の間で非常に人気があるようです。GitはLinuxカーネルの事実上のリポジトリであり、これがC開発者の間で非常に人気がある理由かもしれません。これは、Linux / Unixの世界でのみ機能するという贅沢さを持っている人々に特に当てはまります。

Java開発者はGitよりもMercurialを好むようです。これには2つの理由が考えられます。1つは、JDK自体を含め、非常に大規模なJavaプロジェクトの多くがMercurialでホストされていることです。もう1つは、Mercurialの構造とクリーンなドキュメントがJavaキャンプから来た人々にアピールするのに対し、そのような人々はGitの一貫性のないwrtコマンドの命名とドキュメントの欠如に気づくことです。それは本当だと言っているのではなく、人々はいつもの生息地から何かに慣れてきており、その中からDVCSを選ぶ傾向があると言っています。

Python開発者はほぼすべてMercurialを支持していると思います。MercurialがPythonに基づいているという事実以外に、実際にはその理由はありません。(私もMercurialを使用していますが、なぜ人々がDVCSの実装言語について大騒ぎするのか本当に理解していません。Pythonの言葉が理解できません。それがどこかに記載されているという事実がなかった場合は、 Pythonに基づいているので、私は知りませんでした)。

あるDVCSが別のDVCSよりも言語に適しているとは言えないので、そこから選択すべきではありません。しかし実際には、人々は、コミュニティの一部として最も露出されるDVCSに基づいて(部分的に)選択します。

(いいえ、私は上記の私の主張をバックアップするための使用統計はありません..それはすべて私自身の主観に基づいています)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.