【初心者】【バージョン管理】中央集中型システムと分散型システムについて


## はじめに
ここでは，2つのバージョン管理システム，中央集中型システムと分散型システムについて基本的なことを記述しました．

バージョン管理とは何なのか？SVNとGitの違いは何か？
中央集中型バージョン管理とは？，分散型バージョン管理とは？等のバージョン管理システムについて，基本的なことを知りたい方向けに書いたものになります．
私自身習いたての身であり，まだまだ不十分な点があると思いますが，ご容赦ください．

## バージョン管理とは

バージョン管理とは，一言でいうと成果物の変更を管理することです．
成果物，ドキュメント類の変更を管理することは，複数人で作業を進める上で全体の作業効率を向上することに起因します．
複数の作業者がある1つのエクセルファイルを同時に編集して競合コピーが発生してしまった，など複数の作業者内でのドキュメントの変更・編集による障害を防止するのもバージョン管理システムの役割の1つになります．

成果物(ソースコードやドキュメント類等)は時間が経つにつれて変化あるいは進化していくもので，変化の過程に追従していくことは重要になってきます．なぜなら，どこに誰がいつどんな変更をしたかを知ることは素直に便利であることが多いというのは想像できると思います．

バージョン管理システムが主に3つの機能を提供します．以下の3つ機能は，複数の作業者が同一のファイルを取り扱う上で必要な機能であると考えます．

* ファイルの共有
* ファイルの同期
* ファイルのバックアップ

バージョン管理システムには2つの種類があります．

* 中央集中型システム
   ⇒ Subversion(SVN)，Concurrent Version System(CVS)
* 分散型システム
   ⇒ Git, Mercurial, Bazaar, Fossil 


## 中央集中型バージョン管理システムについて
中央集中型バージョン管理システムの原理について説明します．

複数の作業者が同じファイル群を扱うものとします．
ある1つのサーバで中央集中型システムは稼働し，だれでもそのサーバからファイルのコピーを取得して作業ができます．
変更した内容はサーバにある内容に反映(コミット)できます．
また，他の利用者が更新操作を行ったことにより，サーバ内のファイルが変更されると，その内容も自分の環境に同期できます．ここで，サーバ内にあるファイル群のことをリポジトリと呼びます．
<img width="970" alt="中央集中型VCS.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186620/c4c9c417-dac9-9d57-bb0e-8ea85f620a51.png">


サーバ側では全ての変更過程を記録しているので，この記録をもとにどんな変更でも前の状態に戻したり，変更した時に何が行われたかをわかることができます．

変更をサーバに保存すると**リビジョン番号**というものが生成・増加されます．リビジョン番号は，書籍で例えると，改訂版の番号(第1版，第2.3版等)にあたるようなもので，変更を識別する一意のシンボルになります．

中央集中型のデメリットとして，オフラインの状態では最新のファイルをリポジトリに取得・反映することができません．

## 分散型バージョン管理システム

分散型システムは中央集中型と違って，主となるサーバは持っていません．その代わりに，だれもが独立したリポジトリを用意して，他のリポジトリと同期することができます．中央集中型ではリポジトリを用意できるのは1つのサーバだけでした．それに対し，分散型は複数のリポジトリを持つことができます．
なので，中央集中型ができないことを分散型では可能になります．リポジトリを複数存在することから「分散型」と呼ばれます．

### 分散の戦略
中央集中型のように，ある1つのサーバ(「中央サーバ」と便宜上呼称)にリポジトリを置き，中央サーバから複数の作業者がリポジトリを①ローカルにコピー(「pull」と呼ぶ)→②変更→③中央サーバに反映(「push」と呼ぶ)という流れは分散型でもあります．

ただし，この分散型における中央サーバの目的は中央集中型とは異なります．また，上記の流れは中央集中型と同じ使い方であり，分散型の優位性を活かせていません．



分散型における中央サーバの目的は全ての作業者，開発者が個々の変更を単一の場所で共有・集約する場所となり，**開発者のリポジトリ間**でpullやpushをする代わりに使われます．
このような単一の中央サーバにあるリポジトリ(中央リポジトリ)は，**全ての作業者それぞれのリポジトリにおける**すべての変更を追う為のバックアップにつながります．

分散型バージョン管理システムでは，中央リポジトリでファイルを共有するために中央集中型とは異なるアプローチが可能です．
複数のリポジトリを1つのサーバに用意して，それぞれ異なるレベルでアクセスする方法です．(ここ図がほしいかも)
複数のリポジトリには，開発版リポジトリ，安定板リポジトリ，リリースリポジトリ(リリースごとに用意)，などがあります．

* 開発版リポジトリ:だれもが変更をpushできます．
* 安定板リポジトリ:管理者以外の全員が読み取りのみ可能で，管理者は開発版リポジトリの変更を吟味して，どれを安定版に
取り込むか判断します．
* リリースリポジトリ:リリースごとにリポジトリを用意し，読み取り専用とします．

これにより，メンバーは作業に集中し，マネージャーはその内容を安定版リポジトリに反映する前にレビューを行えます．

## 運用面における中央集中型と分散型のそれぞれの特徴


中央集中型では
全てのユーザはサーバから自分のPCにコピーを，常に中央にあるリポジトリと同期する責任があります．これにより，自分の変更を他のユーザが取得できるようにしておく必要があります．
ローカル(自分のPC)で変更したものと同じファイルをだれかが同時に編集した場合に，中央サーバにチェックイン(変更分を反映)する時点で変更が競合してしまう可能性があります，
また，中央サーバに接続できない環境の場合(例えばネットがつながらない環境)，最新のファイルを取得・反映ができません．

分散型集中型では
ローカルのリポジトリにはそれぞれにリビジョン番号がありますが，全てのリポジトリで一貫した共通のリビジョン番号というものは存在しません．これに対する方法として，タグというもの使って，バージョンの識別をわかりやすくします．タグはいわば，ラベルのようなもので，特定の変更記録にラベルをつけます．
バックアップについて，作業者それぞれが彼らのリポジトリをバックアップする責任が伴います．

## 中央集中型システムの欠点を補うための手法　～ブランチとマージについて～

ブランチとマージがなぜ必要なのか？どういう経緯で生まれた思想なのか，少し知りたくなったので，ちょっと調べてみた結果を記述します．


中央集中型では，時間がかかる複雑な変更を多くのがファイルに行っている場合，全体の作業が完了するまで全ての作業者のPC内のファイル(ローカルファイル)を更新せずに維持しなければなりません。つまり，全体の作業あるいは編集している作業者が完了しないと，自分の作業ができない状態に陥ります．
これにより，以下の問題が浮上します．

* すべての変更は作業者のコンピュータ上で行われ，バックアップができません．
* 全体の作業が完了して中央サーバに反映するまで，他の作業者と変更内容を共有するのが難しくなります．もし全体の作業が全て完了せずに中央サーバに反映してしまうと，リポジトリ内のファイルが不安定な状態になりかねません．これは他の作業者の迷惑になります．

これを解決する手段として，ブランチとマージという手法があります．
これはメインの作業ラインから分岐させて，作業専用のラインを作成し，作業用のラインで作業が完成次第，変更分をまた元のメインのラインに戻す手法です．分岐するラインをブランチにあたり，ブランチからメインのラインに変更を反映することをマージにあたる．
これより，作業者自身の作業専用ラインの変更履歴をたどることでバックアップが容易になると．中央集中型バージョン管理について，このようにコンテキストをたどると少しだけなるほどねーとなりました．

ただし，中央集中型バージョン管理システムには，ブランチとマージを適用できますが，極めて難しい作業であるようです．(引用:エキスパートPythonプログラミング第二版)


## まとめ

* バージョン管理システムは複数の作業者が特定のファイル群を扱い，それらの変更履歴を管理したい場合に使用される，
* バージョン管理管理システムには中央集中型と分散型が存在する．
* 中央集中型ではリポジトリが1つであるのに対し，分散型ではリポジトリが複数存在する．
* 作業効率化，バックアップの効率化を図るためにバージョン管理システムではブランチとマージの手法を適用する．

## 参考文献
* http://hyoshiok.hatenablog.com/entry/20140205/p1
* http://hyoshiok.hatenablog.com/entry/20140205/p1
* エキスパートPythonプログラミング第2版
* https://www.itmedia.co.jp/enterprise/articles/0902/09/news019.html