VCS (Version Control System) を知ろう

9 min read読了の目安(約8300字

書いた動機

  • VCS(Version Control System)  に馴染みの無い人向けに書こうと思いました
  • subversion(svn) や Mercurial(hg)、git に関する解説記事はよく見かけますが、横断して解説する記事をあまり見かけなかったというのも一つです
  • 自分の頭の整理も兼ねています

この文章の趣旨

(十分ケアできているかは怪しいですが ...)

  • 「ブランチ切って、master に PR (プルリク) しといて〜」と言われた時にパニックに陥らないようになる
  • VCS を使ったことがない人がググって情報を仕入れることができるようになる
  • VCS の便利さを実感して使えるようになる
  • subversion の使い方、git の使い方など適宜覚えるのではなく、包括的な知識を持って他の VCS も抵抗なく使えるようになる

解説としての厳密さは重視せず、まずは使えるようになることを目的としています

注意点

  1. 基本的に文章による解説なので長ったらしいかもしれません
  2. 具体的なコマンドや詳細な技術ネタはありません (メタい話ばっかりです)

では、始めていきましょう(∩´∀`)∩

VCS(Version Control System) って何?

文字通り、ファイルやディレクトリのバージョンを管理するためのシステムです

  • 何か特定のツールを指す言葉ではありません。あくまで概念的なものです
    • メモ帳や秀丸などテキストが編集できるツールを包含して、「テキストエディタ」と呼ぶようなものです
  • ソースコードをサーバで共有し、開発者が全員同じコードを参照することができます

※ ソースコードをホスティングするサーバ側のことは今回は考えません
※ あくまで開発で使うツールの一つなので、大げさに考えないようにしてください

なんで VCS が便利なの?

ファイルの変更履歴を残せるから。これに尽きます
変更履歴を残すことで以下のようなメリットがあります

  1. 変更履歴を残すことで過去のバージョンに巻き戻すことができる
    • 一時的にソースコードを編集して、プログラムを走らせて、元の状態に戻すこともできます
  2. ファイルの変更点を明確に把握できる
  3. 「誰が」変更したのか把握できる

ここで、「もしも VCS を使わないで開発を行う場合」の流れを考えてみましょう

VCS を使わないで開発を行う場合

  • 自分の PC 上で VCS を使わない場合、どうやって過去の履歴を残すことができるでしょうか
  • 一つの案として、ファイルの履歴を管理する場合にはディレクトリの名前を変えて、過去のディレクトリを取っておくことが考えられます
ソースコード_2018年03月30日
ソースコード_2018年04月01日
ソースコード_2018年04月02日
...
  • 過去のディレクトリを触って、過去のファイルを上書きしてしまったら地獄ですね。

更に、他の人とファイルを共有することを考えてみましょう

  • zip にして全員にメールで送信する?
    • 開発メンバーが 10人いたら 10人に送信しなければなりません
  • どこかにアップロードして zip をダウンロードしてもらう?
    • 都度変更があった時にサーバにもう一度アップロードして、開発メンバーに知らせなければいけません

これらの問題を解決してくれるのが VCS です

VCS の仕組み

概要図

  • こういった形でサーバにソースコードを配置し、開発者全員で共有します
  • 開発者 A がソースコードを修正してサーバにアップロードして、開発者 B, 開発者 C からも参照ができるようになります
  • 開発者側を「クライアント」、ソースコードが置いてある側を「サーバ」と呼ぶことにします

なんで VCS 専用のソフトをわざわざ使うの?

  • VCS は内部で変更履歴を管理するための独自データを作成しているため
    • svn だと .svn、git だと .git ディレクトリの中身が独自データになっています
  • クライアントとサーバ間でソフトウェア毎に通信の方法が異なるため

補足として、git コマンドや svn コマンドはいわゆるクライアント側のコマンドです (管理用コマンドもありますが)
Windows や Mac 上などで GUI で git や svn を使いたい場合には「git GUI クライアント」などと検索するとよいでしょう

変更履歴って具体的に何?

単純にいってしまえば、テキストの差分を管理しています (もちろんバイナリファイルも管理できます)
テキストの差分というのは、例として上げると

hello

というテキストファイルの「hello」の内容を「world」に改変すると以下のようになります

hello.txt
- hello
+ world

- は削除で + は追加を意味します
このことを「差分」や「diff」と呼びます

これらの差分(行や単語の追加、削除)を積み重ねていったものを「変更履歴」や「commit log」と呼んだりします

VCS を使うときに抑えておくポイント

以下のことを抽象的に理解していれば、どのソフトでもある程度は使うことができるようになります

  • サーバからソースコードをコピーしてくる (clone)
  • 変更したファイル一覧を見る (status)
  • 変更点の差分を確認する (diff)
  • 変更点を追加・削除する (add/rm(remove))
  • 変更点を確定する (commit)
  • サーバに自分が行った変更をアップロードする (push)
  • サーバから最新のコードを取ってくる (update/pull)

各ソフトウェアのコマンドに関しては、文末の「各ソフトウェアのコマンド対応表」に記載しました

覚えておくと良い代表的な用語

  • リポジトリ (repository)
    • ソースコードを格納する(恐らく一番大きな)単位です
    • 大体はプロジェクトごとに分けられて作られるので、プロジェクトで利用するソースコード一式のことだと思っても良いでしょう
  • ブランチ (branch)
    • 直訳すると「枝」ですが、メインで開発しているリポジトリから任意のタイミングで枝を生やすことができます
    • 皆で共有する主要なブランチ(メインライン)から、別の分岐をして開発を進めることができます
    • こちらの解説が分かりやすかったので、ご参考までに
    • 特定のブランチから異なるブランチに変更点を合流させることを「マージ」と呼びます
  • タグ (tag)
    • ある時点でのブランチの状態に名前をつけたものです
      • タグを作る人が自由に名前をつけられます
    • 実用例としてはリリースをするタイミングでメインラインのブランチに対して 「v1.0.0」や「v1.0.1」という名前でタグを作成したりします
    • 納品のタイミングなどでも活用されたりします
    • タグを作ることを「タグを打つ」と言ったりします

VCS の主要なソフト

2018/04/04 現在、主に使われているソフトです
「CVCS or DVCS」としているのは VCS の中でも種類があるためです

ソフトウェア名 CVCS or DVCS デフォルトのメインライン(ブランチ)名
Subversion(svn) CVCS trunk
Mercurial(hg) DVCS default
Git DVCS master
  • CVCS (Centralized Version Control System)

    • 集中型バージョン管理システムと呼ばれます
    • subversion(svn) が代表的なソフトです
    • 変更を確定(commit)すると即時にサーバ側に反映されます
  • DVCS (Distributed Version Control System)

    • 分散型バージョン管理システムと呼ばれます
    • Mercurial(hg)、Git が代表的なソフトです
    • 「分散」というのは、サーバ側とクライアント(ユーザ)側で2つリポジトリが存在するためです
      • サーバ側のリポジトリはリモートリポジトリと呼びます
      • クライアント(ユーザ)側のリポジトリはローカルリポジトリと呼びます
    • CVCS との大きな違いは、サーバ側とクライアント側でリポジトリが 2つあるため <font color="red">commit をしても即座にサーバに反映されません。</font>
      • <font color="red">リモートリポジトリに明示的に push する必要があります</font>
    • Github というホスティングサービスでは git を使って、ソースコードを github.com に置いておくことができます

また、CVCS/DVCS ともメリット・デメリットがあります
こちらの記載が詳しいので参考にしてください

ここからは git と Github を例として DVCS をメインに解説をしていきます

DVCS を自分のものにする

基本的には以下のことができれば、 Mercurial(hg)/Git などを使った開発がスムーズにできるようになります
参考までに git のコマンド例を書いておきます

  1. ブランチを切る
    • git branch 現在のブランチを確認 (ここがブランチを切る基点になる)
    • git chekckout -b <任意のブランチ名> ブランチを作成
  2. 自分が切ったブランチに変更点をコミットする
    • git status 自分が変更したファイル一覧を確認
    • git diff 自分が変更したファイルの詳細な差分を確認
    • git add <ファイル・ディレクトリ名> ファイルを追加
    • git commit 追加したファイルを commit して確定
  3. メインラインに変更があった場合、自分のブランチにマージして、最新の状態に追従する
    • git checkout master メインラインブランチ(master)をアップデートするために、ブランチを移動
    • git pull origin master 最新のメインラインブランチ(master)を取得して、ローカルリポジトリの master ブランチにマージ
    • git checkout <自分のブランチ名> 自分が作ったブランチに移動
    • git merge <メインラインのブランチ名(master など)> 自分が作ったブランチに master ブランチをマージ
  4. 自分のブランチをサーバに送信して、ブランチをリモートリポジトリに反映する
    • git push origin <自分で作ったブランチ名>
  5. メインラインに対して Pull Request を作る
    • Pull Request に関しては、付録の「DVCS が主流になった理由」に記載しています
    • ブランチが作成されていれば、Github の画面上で Pull Request が作成できます
  6. メインラインに対して作成した PR をマージする
    • 自身で Pull Request をマージすることもできます

もちろん、Pull Request を使わずに自分が作成したブランチをメインラインにマージしてサーバに push することもできますが、 Pull Reqeust が使える環境ならば積極的に使っていきましょう
以下はオプションですが、覚えておくと便利です

  • 一時的な変更点を戻す
    • git だと git checkout <ファイル名> hg だと  hg revert <ファイル名>
  • 自分の一時的な変更点を取っておく
    • git だと git stash hg だと hg shelve

衝突(Conflict)

開発者間で同じファイルを編集したりすると、変更の衝突(Conflict)が発生します
具体例として、先述した「メインラインに変更があった場合、自分のブランチにマージして、最新の状態に追従する」タイミングで発生することがあります
衝突が発生した場合には、開発者が衝突を解決する必要があります

衝突した箇所は git status などファイルの状態を見るコマンドで確認できます
衝突の解決は難解ではありません。衝突した場所は <<< などで文字列検索をすれば大体は発見できます
具体的にはファイルが以下のように書き換わっていたりします。

<<<<<<< HEAD
自分の環境の変更点
=======
他の環境での変更点
>>>>>>> [commit id]

ここで自分が意図する変更を残すだけで衝突の解消ができます。
上記の例ですと、「他の環境での変更点」と「自分の環境の変更点」を残したり、削除したりします
もちろん <<<====>>>> なども消して理想状態に持っていきます

そして、再度ファイルの追加(git add など)を実行して commit をすれば衝突の解決をすることができます。

最後に

  • VCS を使うことは難しくはありません
    • 用語が多くて混乱しやすいので、用語が何を指すのかを覚えるようにしましょう
    • (さらに掘り下げると奥が深いのですが ...)
  • ツールの使い方を暗記するのではなく、「自分がこうしたい」という要求ベースで使えたり、調べられるようになっていただければ幸いです
  • 一番の近道は自分がプロジェクトのオーナーになってリポジトリの管理をすることです
    • Github などにアカウントを作って練習してみるのもいいでしょう

付録

各ソフトウェアのコマンド対応表

  • 前述した操作(「VCS において抑えておくポイント」)一覧から各コマンドの対応表を作成してみました
操作 Subversion(svn) Mercurial(hg) Git
サーバからソースコードをコピーしてくる svn checkout hg clone ... git clone ...
変更したファイル一覧を見る svn status hg status git status
変更点した差分を見る svn diff hg diff git diff
変更点を追加する svn add hg add git add
変更点を確定する svn commit hg add git add
サーバに自分が行った変更をアップロードする svn commit 時にアップロードされる hg push git push
サーバから最新のコードを取ってくる svn update hg pull git fetch or git pull

DVCS が主流になった理由

Github によって DVCS の活用が活発になった、とされています ( Git didn’t beat SVN, GitHub did. )
また、Github が主流になったことで、Pull Request ベースの開発が活発になりました

  • Pull Request とは特定のブランチをメインラインブランチなどにマージする前にお伺いを立てる仕組みです
    • Gitlab では「Merge Request」と呼んでいたりします

Pull Request ベースの開発が主流になった理由として、(筆者主観で)以下のようなことがあったからだと考えています

  • 「ブランチを切る」/「ブランチをマージする」ことによる目的ベースの変更
    • Subversion(svn) でも可能ですが、DVCS の方がブランチをライトに作りやすい、というのがあります
    • ブランチを切ることで開発者自身や関係者のみに変更を絞ることができます
  • Pull Request を送るというメリット
    • git というツール単体では Pull Request/Merge Request というものは実現できません
    • 行単位で開発者がコメントして議論したり、マージ前の確認として俯瞰したチェックがしやすいなどのメリットがあります

「差分」という知識を応用しよう

  • VCS が主流になる前は、差分情報をファイルとして保存して、その差分をパッチとして当てる、という文化がありました。(というか、今も現存してます)
  • Linux 上では diffpatch コマンドで差分の作成、パッチ当てができます
    • diff -up [オリジナルソース] [修正後ソース] でパッチファイルを作成
    • 作成したパッチファイルを patch コマンドでパッチを当てる

今回例に挙げなかった VCS

  • RCS(Revision Control System)
    • ローカルでバージョン管理ができるシステムです (コードをホスティングするサーバを必要としません)
    • わざわざコードをサーバにアップロードしないで済むようなケースに利用されたりします
      • サーバ自体の設定変更履歴管理
      • 「特別な事情」でソースコードをホスティングするサーバを用意できない場合
  • CVS(Concurrent Versions System)
    • Subversion(svn) の前身となるシステムです。現在でも使っているプロジェクトはあります。
    • RCS -> CVS -> Subversion(svn) という進化の流れを辿っています
  • 他多数