こんにちは、山本和道です。
本記事は連載「若手エンジニアのためのDevOps入門」の第3回です。

第1回 インフラエンジニアにとってのDevOps
第2回 Webアプリでの開発環境構築
第3回 バージョン管理システム
第4回 継続的インテグレーション/デリバリー
第5回 DevOpsのための道具箱: APIを使いこなす
第6回 リリース/構成管理: 概要

第2回では開発環境や開発時のサーバの構築方法などについて扱いました。
第3回となる今回は、開発で利用される重要なツールであるバージョン管理システムと、バージョン管理システムを利用した開発フローについて扱います。

現在の開発作業においてバージョン管理システムを利用することはもはや当たり前となっている感があります。
複数人によるソースコード修正といったチームでの開発作業においてはバージョン管理システムは非常に便利なものです。
運用側を担当されている方の中にはまだまだ馴染みが薄いという方もいらっしゃるかもしれませんが、
サーバの設定ファイル類やプロビジョニング用スクリプトなどでバージョン管理システムを活用する場面も少なくありません。

DevOpsに取り組む上でインフラエンジニアがバージョン管理システムの概念や基本操作を押さえておくことは非常に有用ですので、
当記事では実際にバージョン管理システムを動かしながら解説を行います。
まずバージョン管理システムの役割や実際のツールの種類/特徴などの基本的な部分から始め、
その後にバージョン管理システムの具体的な利用設計などについて扱うようにします。

バージョン管理システムの概要

バージョン管理システムとは一言で言うと「変更履歴を管理するためのシステム」です。

ファイルの作成/更新日時や編集者、変更内容などを記録/保存しておくことで
過去の特定の時点での状態を確認や変更差分の抽出、特定の時点への復元などの操作を可能としています。

また履歴の保持だけではなく、複数人で変更箇所が重なってしまった際の検出や競合解決のためのサポート機能を提供してくれるものが多いです。

主なバージョン管理システム

バージョン管理システムはオープンソース/プロプライエタリな製品含め多数あります。
その中でもよく使われるバージョン管理システムの例としては以下のようなものがあります。

  • Git
  • SubVersion(svn)
  • CVS

特にgitについては後述するGitHubやGitLabといった周辺サービス/製品も数多く、様々なプロジェクトでの採用例も多いため当記事ではgitを中心に扱います。

バージョン管理システムの基本的な操作

ここからは実際にgitを動かしてみながらバージョン管理システムでの主要な用語や概念、操作などに触れてみます。
なお、当記事ではgit自体のインストールや操作方法などは最低限の説明のみとします。実運用の際は必要に応じてgit入門資料などを別途参照ください。

事前準備: gitのインストール

まずはgitのインストールを行っておきます。
公式サイトからセットアップ用のファイルをダウンロードしてインストール、またはyumやaptといった各プラットフォーム用のパッケージマネージャを利用するなどの方法でgitコマンドのインストールを行っておいてください。

参考: 公式サイト(ダウンロードページ): https://git-scm.com/downloads

リポジトリ

バージョン管理システムでは管理対象の各バージョンのファイルや変更履歴などのメタデータを「リポジトリ」と呼ばれるデータベースに格納しています。
gitの場合は基本的に”.git“というディレクトリにリポジトリが格納されることになります。

リポジトリはローカルマシン上で作成することもありますし、リモートにすでに存在するリポジトリを取得することもあります。
ここでは実際にリポジトリを作成してみます。

リポジトリの作成

まずは作業用のディレクトリを作成します。
コマンドプロンプトやターミナルから以下のコマンドを実行してください。
(以下はmacOSでの例です。WindowsやLinuxをご利用の際は適宜読み替えてください)

 # 作業用のディレクトリ"example-devops"を作成 & 移動
 $ mkdir example-devops; cd example-devops

次に以下のコマンドでリポジトリの初期化が行えます。

$ git init

これでカレントディレクトリの配下に”.git“というディレクトリが作成されます。

ファイルの追加

次にファイルをひとつ作成しgitの管理対象に加えてみます。

まずはファイルの作成を行います。

$ echo "First commit" > example.txt

ファイルを作成しただけの状態ではgitの管理対象として認識されていません。
バージョン管理の状況は以下のコマンドで確認できますので実行してみましょう。

$ git status
On branch master

No commits yet

Untracked files:
 (use "git add ..." to include in what will be committed)

example.txt

nothing added to commit but untracked files present (use "git add" to track)

gitの管理対象としてファイルを追加するには”git add“コマンドを実行します。

$ git add example.txt

この状態で”git status“を実行すると以下のような表示になります。

$ git status
On branch master

No commits yet

Changes to be committed:
 (use "git rm --cached ..." to unstage)

new file: example.txt

git add“で対象のファイルが管理対象となり、”new file“(新規作成されるファイル)という扱いになりました。
現在はgitの管理対象にはなっているものの未確定という状態になっています。

変更を確定するにはコミット(“git commit“コマンド)を行います。

# コミット、-mオプションでコメントを記載する
$ git commit -m"First commit"

これでgit上で変更が確定され、リポジトリに変更が記録されました。
変更履歴は”git log“コマンドで表示できます。”git log“を実行してみると先ほどのコミットが確認できます。

ファイルの変更

次にgitで管理対象となっているファイルを変更してみましょう。
先ほど作成した”example.txt“ファイルをテキストエディタなどで編集してみてください。
編集後、”git status“コマンドを実行すると以下のような表示になります。

$ git status
On branch master
Changes not staged for commit:
 (use "git add ..." to update what will be committed)
 (use "git checkout -- ..." to discard changes in working directory)

modified: example.txt

no changes added to commit (use "git add" and/or "git commit -a")

管理対象のファイルが変更されたことがgitにより検知されています。
この変更をコミットするには”git add“でコミット対象に加える必要があります。(これを「ステージング/ステージする」という言い方をします)
その後コミットすることで変更が確定されます。

# git addでステージする
$ git add example.txt

# ステージした内容をコミットする
$ git commit -m"Second commit"

実際にコミットする手順としては新規作成時でも変更時でも同じ(“git add“して”git commit“)となっています。

実際にgitを利用する際はステージしたファイルの取り消し(“git add“の取り消し)で利用する”git reset“やステージしていないファイルの変更の取り消しで利用する”git checkout“、変更を一時的に退避させる”git stash“といった便利なコマンドも多いため、公式サイトのドキュメントや入門記事、書籍などで一通りの基本的な操作について押さえておくことをお勧めします。

ブランチ

gitにはブランチと呼ばれる、変更履歴を枝分かれさせる機能があります。
ブランチを用いることで、複数人での同時作業を行いやすくしたり、関連する変更をひとまとめにしておくことが可能です。

ブランチの作成、ブランチでの変更作業、枝分かれ元へのマージは以下のような感じで行います。

# 枝分かれしたブランチ"example"を作成しカレントブランチとする
$ git checkout -b example

# exampleブランチでファイル変更&変更をコミット
$ echo "Commit from example" > example.txt
$ git add example.txt
$ git commit -m"Branch example"

# カレントブランチをmasterブランチに変更
$ git checkout master

# exampleブランチをmasterブランチにマージ
$ git merge example

ブランチの扱い方も重要な概念ですので公式サイトのドキュメントや入門記事、書籍などで一通りの基本的な操作について押さえておくことをお勧めします。

リポジトリを他者と共有する(リモートの扱い)

ここまででgitのリポジトリを作成し操作を行って来ました。
このリポジトリを他者と共有するには、

  • 手元のマシンをサーバとして構成した上で接続してもらう
  • gitリポジトリ用のサーバを用意してリポジトリを登録する

といった作業が必要となります。

当記事ではGitHubを利用することでgitリポジトリ用のサーバを用意します。
GitHubはgitリポジトリ用のサーバを提供してくれるサービスで、公開可能(パブリック)なプロジェクトであれば無償で利用可能です。
なお、GitHubについてはgitリポジトリの提供以外にも様々なサービスが付属していますが、それらについては後ほど改めて扱います。

GitHub上にアカウント作成

まずはGitHubを利用するためにアカウントを作成する必要があります。
まだアカウントを持っていない場合は以下のページからアカウントの作成をおこなってください。

GitHub サインアップ: https://github.com/

アカウント作成後はSSH接続用のキーペアの作成/登録を行っておくとローカルマシン上でのリモート操作が楽になりますが
当記事では割愛します。必要に応じて設定しておいてください。

GitHub上に新規リポジトリを作成

次に新規リポジトリを作成します。以下URLからリポジトリの作成を行ってください。

GitHub リポジトリ作成: https://github.com/new

リポジトリの名前は”example-devops“としてください。

作成後にリポジトリのURLが表示されますので控えておきます。

リモートリポジトリの追加

続いて手元のマシン上に作成したリポジトリをGitHub上のリポジトリと関連づけます。
git remote add“コマンドで先ほど控えておいたGitHub上のリポジトリのURLを指定します。

$ git remote add origin <先ほど控えたGitHub上のリポジトリのURL>

これで”origin“という名前でリモートリポジトリが登録されました。
次に手元のマシン上のリポジトリに対して行った変更をリモートリポジトリに反映します。
反映には”git push“コマンドを用います。

# リモートリポジトリoriginに対しmasterブランチの内容を反映
$ git push origin master

git push“とは逆にリモートリポジトリの内容を手元のマシン上のリポジトリに反映するには”git pull“コマンドを用います。

# リモートリポジトリoriginの内容を手元のマシン上のリポジトリに反映
$ git pull origin master

ここまででgitの基本的な操作を扱いました。
DevOpsに取り組む際はバージョン管理システムを日常的に扱うことになりますので基本的な操作については一通りマスターしておきましょう。

バージョン管理の対象とトレードオフ

続いてバージョン管理システムにて何を管理するかという問題について扱います。
単純に考えた場合、アプリケーションに関連するファイル全部を管理対象としても良いかもしれませんが
例えばアプリケーションのログファイルや実行時に生成される一時ファイルなどは管理する意味合いがほとんどないので、ある程度対象を限定するのが現実的です。

管理対象ファイルを決める指針としては以下のようなルールを基本として適宜判断すると良いでしょう。

  • 基本的に全てのファイルを管理対象に
  • 実行時に動的に生成されるファイルは対象外に(例: ログファイルやロックファイルなどの一時ファイル)
  • ソースファイルや定義ファイルから生成/取得が可能なファイルについては適宜判断
  • DB接続情報などの設定類は適宜判断

ログファイルについては追記/蓄積していくものなので(別途管理は必要ですが)履歴管理は不要なことが多いです。
一時ファイルについては実行の都度作成/削除されるなど、変更されることを前提にしているのでこれも管理不要なことが多いでしょう。

適宜判断が必要なのはソースコードや定義ファイルから生成/取得が可能なファイルについてです。
対象としては以下のようなものがあります。

  • exeやdllなどのビルド成果物
  • 最適化後のjs/css/画像など
  • ツールなどで生成されるソースコードそのもの
  • 依存ライブラリのソースコード/実行ファイル/jarなどのアーカイブなど

exeやdllファイルなどソースコードからビルドした成果物やjs/css/画像などの最適化後の静的アセットファイルなどはバージョン管理システムにて管理せずとも(開発環境さえあれば)ほぼ再現可能なため基本的に管理対象から除外しても良いでしょう。
管理対象とした場合は、リポジトリのクローンやチェックアウトのみで実行可能な状態にできるなどのメリットがありますが
ソースコード類とビルド後の成果物のバージョン差異が発生する可能性があったり、
成果物のファイルサイズによってはリポジトリのサイズが大きくなってしまいクローン/チェックアウト操作などに時間がかかるといったデメリットもあります。
成果物についてはCI/CDの仕組みに任せてしまうのも手ですし、
ビルドフックなどを利用してソースコードのコミットと同時にビルド&コミットすることでソースコードとビルド成果物のバージョン差異を防ぐという手もあります。

プロジェクトの規模や開発環境、CI/CDの仕組みなどとのバランスを考慮して適宜管理対象とするか検討してみてください。

管理対象からの除外

gitであれば”.gitignore“というファイルに管理対象から除外するためのルールを記載することが可能です。
一から”.gitignore“ファイルを作成するのは大変ですので、以下のようなサイトで公開されているテンプレートの活用も検討してみてください。

https://github.com/github/gitignore

また、これらのルールに加え、セキュリティ要件やリポジトリの公開有無なども考慮して管理対象を決定します。

バージョン管理システムをより使いやすくするための周辺サービス/システム

gitなどのバージョン管理システム単体で利用しても良いのですが、より便利に使うための周辺サービスやシステムがありますので是非活用しましょう。

GitHub

GitHubはgitリポジトリの提供を行ってくれるSaaSです。リポジトリの提供以外にも様々な便利機能があります。
以下に提供されている機能を一部抜粋しています。

  • リポジトリ内のファイルの一覧/閲覧
  • 履歴や変更差分のグラフィカルな表示
  • プルリクエスト/コードレビュー機能
  • 他システムと連携するためのフックやAPIの提供
  • リポジトリ操作の権限設定
  • GitHub Pagesによる静的ページの公開

基本的にはオープンソースのプロジェクトについては無償で利用可能です。
有償プランではありますがプライベートなリポジトリを作成したり、GitHubを自前のサーバにインストールして利用できるGitHub Enterpriseといったものも用意されていますので必要に応じてプランを選択して利用します。

GitLab

GitHubと類似のサービスとなっていますが、CI/CDの仕組みやDockerイメージのリポジトリ機能などGitLabならではの機能も持っています。
GitHubと同じくSaaSとして利用したり自前のサーバにインストールして利用することも可能です。
無償利用できる範囲がGitHubより広いのもポイントです。

当記事では各機能の詳細については触れませんが、プルリクエスト(GitHub)/マージリクエスト(GitLab)については利用することも多いと思いますので一通りドキュメントなどを通じて機能を押さえておくことをお勧めします。

Gitを用いた開発プロセスモデル/ツール

gitを開発に利用する場合にどのようにブランチを切るかやプルリクエスト/レビューをどう運用するかといった運用の指針としてGit flowやGitHub flowを用いることがあります。

当記事ではそれぞれの詳細については触れませんが、DevOpsに取り組む上でデプロイ/リリースへの取り組み方を理解しておくことは重要ですので概要を押さえておくことをお勧めします。

DevOpsプロセスへの統合

開発したものを迅速にリリースするには各種作業を自動化しておくのが効果的です。
例えばgitの持つフック機能を用いてmasterブランチにpushされたらリリース作業を行ったり、
GitHubとTravisCIを用いてCI/CDを行うといった方法があります。

CI/CDとの連携については次回「継続的インテブレーション/デリバリー」にてTravisCIを例として扱います。

まとめ

今回はバージョン管理システムの概要とgitの基本的な概念や運用方法、連携サービスとしてのGitHubなどの紹介を行いました。
次回はバージョン管理システムと連携する継続的インテグレーション/デリバリー(CI/CD)について扱う予定です。

以上です。