svnとgitのコマンド比較

配属された研究室あるいは職場などで共同作業をする時に、svnやgitなどのバージョン管理システム(Version Control System:VCS)を使う機会が多くなると思います。

最近では、Googleをはじめ多くの企業が大規模プロジェクトでgitによるVCSを採用しており、svnからgitに移行する人が多くなっているとの事でした。それで、コマンドの対応表なんかあったら便利だろうと思ってブログを書いていたのですが、自分が作ろうとしている内容と似たようなサイトをいくつか散見してしまい、急に面倒くさくなって更新が遅れてました(汗)。新規性を発揮するのって難しいものですね、研究でもブログでも…

それでも今回は、一応、自分なりにsvnとgitについてまとめてみることにしました。

ここで最初に断っておきますが、分散管理型VCS(後述)には他にmercurialやbazzarなどがあります。しかし、世の中のシェアを見てみると、どうやら

git > mercurial > bazzar

のようなので今回はgitだけを中央管理型VCS(後述)であるsvnの比較対象として扱うことにしました。

VCSでは、「バージョン」やら「リポジトリ」やら難しい単語が出てきますが、ちゃんと使えるようになると非常に便利な機能だと思うので、ぜひこの機会に使い方を覚えてしまいましょう!
(あと、結構あやふやなので間違ってる可能性もあります。指摘して頂ければ修正致します。)

■語句の説明
まず、今回よく出てくる語句について簡単に説明しておきます。

  • バージョン:プログラムが最初に開発されてから何回修正されたかを示す番号のこと
  • リポジトリ:ファイルの履歴情報などがファイルシステムツリーの形で保存されたデータベースのこと
  • リビジョン:リポジトリ全体に付けられる変更後の状態を表す番号のこと
  • 作業(ワーキング)コピー:既存のリポジトリから複製した自分だけのローカルなリポジトリのこと

svnとgitの比較
そもそもsvnとgitの違いは何なのかというと、svnは中央管理型、gitは分散管理型のバージョン管理システムであるということで、svnは中央のリポジトリに対してコミットを行っていくのに対して、gitは各ユーザが持つローカルのリポジトリに対してコミットを行います。

gitでは、ローカルのリポジトリの内容を中央のリポジトリに反映したり、他のユーザが持つリポジトリを取得したり反映したりできるので、あらゆる環境で分散して管理できます。ローカルにリポジトリがあるので、ノートPCを持ってどこでも開発することができますし、コミットしてもローカルリポジトリに反映されるだけなので、気軽に何度でもコミットできるのも便利です。そして、本当に必要な変更だけをマスターリポジトリに反映させて履歴に残すことができるのです。

しかし、gitはsvnに比べて自分が管理者になる必要がある分だけ覚えなければならない事も多く、コマンドも多くて複雑です。
このため、初心者にとって敷居が高いように感じられますが、svnに慣れていればそんなに難しいことはないと思います。

ここで、細かい操作方法の説明に入る前にsvnとgitの違いについて簡単に箇条書きにしてみました。
以下のsvnとgitの各番号はそれぞれ対応関係にあるものとします。

svn

  1. 中央管理型VCS(中央リポジトリ)
  2. コミットはマスターリポジトリに対して行う
  3. コミットしたらすぐに反映される
  4. addを行うのは新規のファイルを追加する時だけ
  5. リビジョン番号は10進数の数値
  6. .svnディレクトリがサブディレクトリにまで展開される
    (Subversion 1.7よりルートディレクトリにのみ.svnディレクトリが作成されるようになりました。)←2013/5/8追加
  7. ファイルやディレクトリの移動を行うときはsvn copyやsvn moveコマンドを使う必要がある
    (.svnが全ディレクトリに展開されるため)
  8. ファイルロック機能がある

git

  1. 分散管理型VCS(分散リポジトリ)
  2. コミットはローカルリポジトリに対して行う
  3. コミットしてもローカルリポジトリに反映されるだけ(マスターリポジトリに反映させるためにはpushを行う(2段階))
  4. コミットの前に毎回addする必要がある
  5. リビジョン番号は16進数のハッシュ値
  6. 「ローカル」「インデックス」「ローカルリポジトリ」「マスターリポジトリ」の4つ
  7. .gitディレクトリがルートディレクトリにのみ置かれる
  8. 通常通りエクスプローラでドラッグ&ドロップするだけで、ファイルやディレクトリのコピー/移動ができる。
    もちろんコマンドを使っても良い
  9. ファイルロック機能はない

svnとgitの操作方法
以下では、特定のタスクを行うコマンドを左側にsvn、右側にgitで示すことにしました。これらのコマンドはほぼ同じ動作をするものです。

また、説明を簡略化するために、以下のように文字を定義しておきました。

リポジトリのURL形式
リポジトリは情報をファイルシステムツリーの形で保持します。
svnやgitではリポジトリにアクセスするための場所はURLによって表現され、以下のような形式があります。

・主なリポジトリのURL形式

リポジトリの作成

svnやgitリポジトリを作成する。これをやらないと何も始まらない。

svnの場合 gitの場合
$ svnadmin create [REPO] $ cd [REPO]
$ git init

git initコマンドを実行すると、カレントディレクトリに.gitディレクトリが作成され、gitリポジトリの管理ファイルがこの中に作成される。(なお、古いバージョンのgitの場合には、git init dbコマンドで実行するらしい。)

また、svnやgitでは以下のようなディレクトリを各プロジェクトのルートディレクトリ直下に作成する慣習になっている。

svn

  • trunk/:プロジェクトのメインとなるソースコードを管理して開発を進めていくところ
  • branches/:メインのソースコードに対して変更を行う場合にtrunk/から派生させて保存しておくところ
  • tags/:新バージョンをリリースする時などにその時点でのスナップショットを保存しておくところ

git

  • branches/:svnのtrunk/やbranches/を兼ねたようなところ
  • tags/:新バーションをリリースする時などにその時点でのスナップショットを保存しておくところ

gitにはtrunk/という概念はなく、branch間で主従関係を決めることでtrunk/(masterと呼ばれるベースになる主branch)の代わりを設けている。
リポジトリが複数プロジェクトを含む場合は、プロジェクトごとにレイアウトをインデックス化する。

モジュールの登録

新しいプロジェクトをリポジトリに登録する。

svnの場合 gitの場合
$ svn import [URL] $ git add .
$ git commit

svnでは登録時にディレクトリをURLで指定することができる。

作業コピーの取り出し

作業コピーをリポジトリから取り出すためにはsvn checkout/git cloneコマンドを用いる。

svnの場合 gitの場合
$ svn checkout [URL] ([DIR]) $ git clone [URL] ([DIR])

取り出し時にディレクトリをURLで指定する。また、作成するディレクトリ名を指定することもできる。
最新のリビジョンを取得するだけの目的でgit cloneコマンドを実行する場合は、「--depth」オプションで取得するリビジョン数を指定する。

どのリポジトリからcheckout/cloneしたかは次のコマンドで分かる。

svnの場合 gitの場合
$ svn info $ cd [REPO]
$ git remote -v

svn infoコマンドはsvnにしかない機能(git infoコマンドはない)であり、gitにおけるリポジトリの各種設定の情報は.git/config内に記録される。したがって、gitでは.git/config内を調べる必要があるのだが、サブディレクトリにいる時には開くまでが面倒であり、ファイルの中身が多すぎてURLを見つけ出すのも大変である。そこで、git configのgetでURLを取得する。

$ git config --list
$ emacs ~/.gitconfig
[alias]
url = config --get [URL]
$ git url

あるいはもっと簡単に、git remoteコマンドでURLを表示することもできる。
このコマンドでは複数のリモートサーバーを設定していればそれら全てのURLが表示される。

作業コピーの状態表示

作業コピーに加えられた変更点を表示するためにはsvn status/git statusコマンドを用いる。

svnの場合 gitの場合
$ svn status $ git status

引数なしで実行するとツリー全体の変更を表示できる。

ここで、svn statusコマンドの出力の行頭5桁の意味は以下のようになる。
1桁目ー追加/削除/変更など

  • ' ':no modifications
  • 'A':Added
  • 'C':Conflicted
  • 'D':Deleted
  • 'G':Merged
  • 'I':Ignored
  • 'M':Modified
  • 'R':Replaced
  • 'X':item is unversioned, but is used by an externals definition
  • '?':item is not under version control
  • '!':item is missing (removed by non-svn command) or incomplete
  • '~':versioned item obstructed by some item of a different kind

2桁目ーファイルやディレクトリの属性

  • ' ':no modifications
  • 'C':Conflicted
  • 'M':Modified

3桁目ー作業コピーのロック

  • ' ':not locked
  • 'L':locked

4桁目ー履歴付きの追加予告

  • ' ':no history scheduled with commit
  • '+':history scheduled with commit

5桁目ー作業コピーからブランチへのスイッチ

  • ' ':normal
  • 'S':switched

履歴の表示

ファイルやディレクトリの履歴を表示するためにはsvn log/git logコマンドを用いる。

svnの場合 gitの場合
$ svn log | less $ git log

コミットログは新しいものから順に表示される。

また、ファイル名やディレクトリ名を指定して履歴を見ることもできる。

svnの場合 gitの場合
$ svn log [FILE/DIR] $ git log [FILE/DIR]

特定のファイル/ディレクトリをその過去のバージョンと比較する場合、どのバージョンのファイル/ディレクトリと比較するかはリビジョン番号で指定する。

作業コピーの変更点の差分表示

ファイルに加えられた変更点を調べるためにはsvn diff/git diffコマンドを用いる。

svnの場合 gitの場合
$ svn diff | less $ git diff

また、リビジョン番号やURLを指定して変更点の差分を見ることもできる。

svnの場合 gitの場合
$ svn diff -r [REV] [URL] $ git diff [REV] [URL]

作業コピーの編集の取消

編集を取り消して最後にアップデートまたはコミットした内容に作業コピーを戻すためにはsvn revert/git checkoutコマンドを用いる。

svnの場合 gitの場合
$ svn revert [URL/REV] $ git checkout [URL/REV]

作業コピーの編集の反映

ファイル編集後に変更点をリポジトリに反映させるためにはsvn commit/git commitコマンドを用いる。

svnの場合 gitの場合
$ svn commit $ git commit -a
$ git push [URL]

git commit -aコマンドによりローカルリポジトリにコミットし(「-a」オプションにより変更が加えられたファイルを自動検出する)、その後にgit push [URL]コマンドにより他人のリポジトリにコミットする手順となる。
git pushコマンドにより自分の作業コピーの変更を他の作業コピーにも反映させる。

また、以下のようなオプションを任意で指定することができる。

  • --message(-m):ログメッセージの指定
  • --file:ファイル名の指定

ツリーの変更

・アイテムの追加
ファイルやディレクトリを追加するためにはsvn add/git addコマンドを用いる。

svnの場合 gitの場合
$ svn add [FILE] $ git add [FILE]
$ svn mkdir [DIR] $ git mkdir [DIR]

ただし、svn addコマンドはファイルやディレクトリをリポジトリに追加予告するだけで、リポジトリへの登録はコミットで行われる。
ディレクトリを追加するにはmkdirコマンドでディレクトリを作成しておいてsvn add/git addコマンドで作成する方法とsvn mkdir/git mkdirコマンドで一気にやってしまう方法がある。

・アイテムの削除
ファイルやディレクトリを削除するためにはsvn rm/git rmコマンドを用いる。

svnの場合 gitの場合
$ svn rm [FILE] $ git rm [FILE]

ファイルの場合は作業コピーから直ちに削除されるが、ディレクトリの場合は削除予告されるだけである。
また、ディレクトリを削除するためには予めディレクトリの中身を空にしておく必要がある。

・アイテムのコピー
新しいアイテムを作るためにはsvn copy/git copyコマンドを用いる。

svnの場合 gitの場合
$ svn copy [FILE] $ git copy [FILE]

 
・アイテムの移動
アイテムの移動または名前の変更を行うためにはsvn mv/git mvコマンドを用いる。

svnの場合 gitの場合
$ svn mv [FILE] $ git mv [FILE]

ただし、svn moveは中間ディレクトリを作成しない。

作業コピーの更新

他の作業コピーで行われたリポジトリの変更を自分の作業コピーに反映させるためにはsvn update/git pullコマンドを用いる。

svnの場合 gitの場合
$ svn update $ git pull

本当なら変更点の取り出し元リポジトリのURLを指定する必要があるが、svn checkout/git cloneコマンドで作成したリポジトリの場合、複製元リポジトリのURLが自動的に記録される。そのためsvn update/git pullコマンドを実行する場合は上記のように取り出し元リポジトリを指定しなくてもよいことになる。

また、

svnの場合 gitの場合
$ svn update -r [REPO] $ git checkout [REPO]
$ svn update $ git checkout [現在のbranch]

ファイルに対する変更は行頭に表示される1文字のコードで示される。

  • A:Added
  • D:Deleted
  • U:Updated
  • C:Conflict
  • G:Merged

ブランチの作成・管理

・ブランチ情報の表示およびブランチの作成
現在のソースツリーを元に新たなブランチの作成を行うためにはsvn copy/git branchコマンドを用いる。

svnの場合 gitの場合
$ svn copy [trunkURL] [branchURL] $ git branch [branchFILE]

 
・ブランチの切り替え
操作対象とするブランチの切り替えを行うためにはsvn switch/git checkoutコマンドを用いる。

svnの場合 gitの場合
$ svn switch [branchURL] $ git checkout [branchFILE]

なお、gitでは「-b」オプションにより新たにブランチを作成してそのブランチに切り替える作業をgit checkout -b [branchFILE]のように1つのコマンドで実行することができる。

・ブランチ履歴の表示
ブランチ履歴の表示を行うためにはsvn list/git show-branchコマンドを用いる。

svnの場合 gitの場合
$ svn list [branchDIR] $ git show-branch

gitでは、前半の「---」までがブランチ履歴、「---」から後半が最近のコミット履歴を表している。ブランチを階層構造で表示し、「*」が付いている行が現在の作業ブランチとなる。

svnとgitのコマンド体系は似ているところがありますが、…

■各種機能
svnとの連携
今までsvnとgitを比較してきて、冒頭ではgitに移行した方がいい的な発言をしましたが、実は分散管理型VCSを利用する場合でも、成果物を共有する拠り所として中央管理型VCSが必要になります。例えば、svnのファイルロック機能は有効です。

  • git-svn
    gitには、gitリポジトリsvnリポジトリを同期させるgit svnコマンドがある。
    マスターリポジトリとしてsvnを利用して、各自の作業を行うローカルリポジトリにgitを利用することにより、各自のローカルリポジトリを管理するツールを変更してもマスターリポジトリに影響を与えず、新しくツールを覚えたくない場合にはsvnクライアントを従来通りに利用することができる。
    Macportsでインストールする場合、普通にgit-coreをインストールしてもgit svnは有効にならないので、

$ sudo port install git-core +svn

とする必要がある。
ここではこれ以上の具体的な利用方法についての説明は行わない。

GUIツール

無料リポジトリ

■参考にしたページ
あとでまとめて更新しておきます。