バージョン管理システム (VCS) の代表的なものとして、 Git と SVN の2つがあります。これらのうちどちらを採用すべきか考えていきます。
結論から言うと、以下のように使い分けるのがよいと思います。
- テキストファイルなら Git
- バイナリファイルのみなら SVN
コミットについて
先に Git と SVN の話をする際に混乱しやすい「コミット」の違いについて記述しておきます。
SVN でのコミットは、修正ファイルとコメントを記録してサーバー上にも反映します。
対して Git のコミットはローカルにのみ反映され、サーバーには反映されません。サーバー上に反映するには追加でプッシュ操作が必要です。
つまり「SVN のコミット」は「Git のコミット&プッシュ」に相当するという事です。
余談ですが、 Git と SVN は全く概念が異なるので、 SVN と同じような物だろうと思っていると痛い目を見ます(見ました)。別物として1から学習するべきです。
Git のメリット
Git のメリットは沢山の方によって語られているのでここでは少し説明するのみとします。私が Git をお勧めする理由は以下の2点です。
- ブランチを切りやすい
- 課題管理サービスが充実 (GitHub など)
Git はブランチが切りやすい
SVN でブランチを切る場合はディレクトリのコピーが作成されますが、Git はブランチを切った段階ではブランチのメタ情報が書き込まれるのみです。SVN より圧倒的に動作が軽量であり、Git は気軽にブランチを作成することができます。
ブランチを切ると何がいいのかというと、「レビュー」がしやすくなります。SVN では自分のコミットや他人のコミットがごちゃまぜになりますが、 Git ではブランチを切りそこに自分のコミットをまとめることで、自分の修正分が分かりやすくなります。
またブランチを分けることで、レビュー済みのファイルと未レビューのファイルを分離することができ、レビューするまでマージ不可という運用ルールにすれば品質の向上が期待できます。
課題管理サービスが充実
Git 単体でも素晴らしいのですが、 それを利用したサービスが充実しているのも Git をお勧めする理由の1つです。
VCS を自分で立ち上げる場合はサーバーの立ち上げや管理で結構手間がかかります。しかし GitHub, GitLab などのサービスを使うことで画面からの操作で簡単にリポジトリを作成することが可能です。
また、前述の「レビューをするまでマージできないルールの運用」を設定変更で簡単に実現することができます。Git 単体ではルールを守らない操作をすることができてしまいますが、レビュー済み (main) ブランチを保護する設定を入れることで、簡単に運用ルールの徹底をすることができます。
また、 Git にはないプルリクエスト(マージリクエスト)機能を使うことで、レビューがより簡単に実施できるようになります。
SVN はバイナリ向き
Git の利点を紹介しましたが、これらの利点が生かされるのは管理するファイルがテキストファイルであることが前提です。テキストファイルとはテキストエディタで開ける形式で、ソースコードなどがそれにあたります。バイナリファイルはテキストエディタで開けない形式、つまり 画像や Excel ファイルなどです。
Git LFS という機能を使えば Git でもバイナリのファイル管理はできるのですが、デメリットが存在します。
バイナリファイルはロックが必須
バイナリファイルは差分がとれないため、マージができません。A さんが編集したファイルを B さんが同時に編集すると確実にコンフリクト(競合)が発生します。テキストファイルの場合は編集した行が被らなければマージ可能ですし競合しても目視で修正が可能なのですが、バイナリファイルはそれができません。
そのため、一般的にバイナリファイルを編集する場合はファイルをロックします。ロックすることで自分以外は編集できないようにして競合を防ぎます。
Git はロック機能が複雑
SVN にも Git にもロック機能は存在します。SVN の場合はファイルをロックすると、自分がアンロックまたはファイルをコミットするまで他の人がファイルをコミットすることはできません。
Git のロック機能も同様に動くのですが、少し癖があります。Git の場合はロックを取得するまで、ローカルのファイルが読み取り専用として設定されます。ただこの読み取り専用はファイルのプロパティとして設定されるだけなので、読み取り専用のチェックを外せば容易にローカルで編集・コミットすることができます。

もちろん、他の人がロック中のファイルをプッシュするとブロックされるのですが、ローカルでのコミットは実質自由に行えるため不整合が起こる可能性はあります。
Unable to push locked files:
* binary.ext - zu-min-g (refs: main)
Pushing to https://github.com/zu-min-g/xxxx.git
ERROR: Cannot update locked files.
error: failed to push some refs to 'https://github.com/zu-min-g/xxxx.git'
また、ロックを使用してもブランチの切り方によっては競合が発生します。競合が発生しないようなブランチの運用ルールを作ってみたが煩雑に感じて、 main ブランチしか使わなくなる運用になり、 SVN と変わらない利用方法となるケースがあります。1運用ルールについてはこのページが参考になります。
また、プッシュやマージ時に自動でアンロックされないので、修正が取り込まれたら手動でアンロックしなければなりません。2自動アンロックについての議論はここで行われているようです。
結論
私の中での結論は以下のようになりました。
- 基本は Git
- Git でのバイナリファイル管理が面倒に感じる、かつ SVN の導入が面倒ではない場合は SVN
Git の方が好みですが、バイナリファイルに関しては SVN の方が考えること少なくて楽だなと思いました。
ただ、 Git LFS を使い込んだことがあまりないので、慣れればバイナリも Git のほうがよかったとなるかもしれません。