対象読者
- これからGitやGitHubを使い始めようと思っている方
- Gitの使い方は知っているが、チーム開発の経験がない方
Gitによるチーム開発のいろは
第1回ではGitの基本的な使い方を解説しました。第2回では、実務・チーム開発の現場でGit、およびGitHubを活用するためのノウハウを紹介します。とはいえあくまで一例なので、自分たちの開発チームに合わせたやり方に適宜カスタマイズしてみてください。
GitHubは、Gitリポジトリのリモートホスティングサービスの1つであり、Gitでチーム開発を行う上で欠かせないものです。GitHubについても後半の節で解説します。
Gitの誕生秘話
まず余談ですが、Gitの誕生秘話について少し触れておきます。そもそもGitはLinuxを開発するために生まれました。つまり、Linuxほど大規模なプロジェクトを、大人数で進められることが要件としてありました。
こういった要件を満たし、無料で使えるVCSが当時存在しなかったため、リーナス・トーバルズ氏が自作に踏み切り、その後、わずか2週間程度で作りあげられたという逸話もあります。
経緯についての詳細は、Git略史に記載されているので、興味がある方はそちらも読んでみてください。
Gitの特徴
Gitはこういった背景から誕生したため、Git以前のVCSに比べて次の特徴があります。
- 高速な merge と checkout
- 分散型
- branch
高速な merge と checkout
Gitでmerge
やcheckout
コマンドを実行したことがある方は、その速さに驚いたことはないでしょうか?
どんなに遠い過去のバージョンにcheckout
しても、コミットが大量に積まれているブランチをmerge
したとしても、その処理時間で待たされることはほとんどありません。
一見、履歴が遠ければ遠いほど、差分のmerge
に時間がかかり、checkout
による過去バージョンの復元に時間がかかると思われるかもしれません。
ただし、実際には「履歴の遠さ」はこれらのサブコマンドの実行時間に影響を与えません(その代わり、変更されているファイル数に依存します)。この理由については第3回のGitの内部構造に関する記事で紹介します。
分散型
VCSには大きく分けて、集中型と分散型の2つがあります。Gitは分散型を採用しており、これが大人数で開発を進めることができる大きな要因の一つです。
それぞれの特徴は以下の通りです。
-
集中型VCS
-
リポジトリはサーバーが管理する
- リポジトリのこれまでの全履歴やファイルはサーバーのみ持つ
-
作業者は自分が触りたいファイルだけをローカルにコピーし、変更後にサーバーにpushする
- 作業中のファイルは他の人は触れないため、大人数で開発すると効率が低下
-
リポジトリはサーバーが管理する
-
分散型VCS
- リポジトリの全履歴を含めた完全なコピーをローカルに持つ
- 誰がどんな作業をしていても無視して独立に作業を進められる
branch
branchも大人数で並行して開発を進めるための、Gitの重要な機能です。こちらは第1回で解説しているので省略します。
ただし、チーム開発をする上でbranchの使い方は重要です。無秩序にbranchを使うと、どこでどの機能が実装されているか分からなくなる上に、mergeの際にコンフリクトが発生しやすくなります。また、最新版がどれかも分からなくなります。
そういった問題を防ぐために、ブランチ戦略(ブランチの運用方法)にはさまざまな方法論があります。
ブランチ戦略
それではここからはブランチ戦略のいくつかの方法論について解説します。
これらの方法論に厳密に従う必要はないですが、参考にしつつ、各開発チームで使いやすいようにアレンジしてください。
リモートリポジトリ
Gitは分散型と言いましたが、分散型VCSも実際には、集中型と同様にサーバーにもリポジトリを用意し、そのリポジトリを通じて他の開発者に作業履歴を共有していきます。Gitではこれをリモートリポジトリと呼んでいます。リモートリポジトリのホスティングサービスとしては、一般的にはGitHubやGitLab、BitBucketなどが利用されています。
これから紹介していくブランチ運用の方法論も、まず皆でリモートリポジトリを1つ決めて、Gitを中央集権的に扱えるようにしていることが前提となります。こうすることで、集中型と分散型の良いとこどりができます。
リモートリポジトリの設定は以下のコマンドで行います。
# 例:GitHubにあるリポジトリを登録 $ git remote add origin git@github.com:tonouchi510/git-tutorial.git
Git Flow
Git Flowは最も一般的なブランチ戦略になります。Git Flowという名前は知らなくても、慣習として似たようなことをしている人も多いと思います。また、Git Flowを少しアレンジして使っているのもよく聞きます。
Git Flowを図にすると以下の通りです。全体像はかなり複雑なので、ここから重要な部分だけピックアップして解説していきます。
まず、Git Flowで最も重要なのが、main(旧master)ブランチとdevelopブランチの関係です。developブランチはmainブランチから分岐し、開発はdevelopで行って、本番にリリースする時のみ main にmerge
されます。
ソフトウェア開発の現場では、ソースコードを本番環境にリリースする前に、開発環境/ステージング環境にデプロイして動作検証するのが慣習としてありますが、developブランチは開発環境、mainは本番環境にデプロイするためのブランチとして使われます。
次に、複数人で並列に開発を進めるために分岐するブランチである、featureブランチについて解説します。
こちらはdevelopブランチから、1機能ごとに短命のブランチを切ります。機能の開発が終わったら、developにmerge
します。「1 機能 = 1 feature branch」を守らないと、どの機能がどのブランチに入っているかが分からなくなるほか、差分が大きくなってコンフリクトも発生しやすくなってしまいます。
また、問題が生じてrevert
する際も、機能単位でrevert
したいことがほとんどだと思うので、1つのブランチに1つの機能を守るのがおすすめです。大きい機能の場合はfeatureブランチからさらにfeatureブランチを切って、できるだけ小さい単位でmergeしていくのがおすすめです。
ここまでで基本的なブランチの切り方について解説しました。ここまでの内容だけでも十分開発を進められると思います。Git Flowを意識していなくても、main/develop/featureのブランチの切り方をしている開発チームは多いと思います。
Git Flowではこれに加えてreleaseブランチやhotfixブランチがあります。それぞれ以下の用途で使われます。
-
release
-
developからmainへ
merge
するための準備をするブランチ -
使われ方はチームによってまちまち
- 例:bugfixやversion表記の更新、AppleやGoogleの審査用途
- stagingという呼ばれ方も
-
developからmainへ
-
hotfix
- 本番環境で発生したバグのうち、緊急性が高いものを修正するためのブランチ
- 工程を短縮するために、mainブランチから直接ブランチを切る
-
hotfixからmainに
merge
する際にはpatchバージョンを上げることが多い
この辺りのブランチはチームでの必要性に応じて使い分けてみてください。
トランクベース開発
Gitのブランチ戦略には、Git Flow以外にもさまざまなものが提案されています。
その中で、Git Flowとは対極的に、かなりシンプルなブランチ戦略であるトランクベース開発についても解説しておきます。Git Flowは便利な一方で、複雑にブランチが入り組むとコンフリクトしやすい問題もあります。コンフリクトが起きると、解消のために無駄に時間を費やすことになってしまいます。トランクベース開発は、できるだけコンフリクトを起こさないようにしたいというところから生まれています。
トランクベース開発では、開発者は1つのブランチ(main)上で開発し変更を直接Pushするか、極めて短命のブランチであることを前提としてブランチを切り、そこで開発を行います。
ブランチが複数あり、長期間存在することがコンフリクト発生のリスクを上げているので、それらをできるだけ回避するという考え方です。GitFlowと比べるとかなり極端な考え方ですし、問題なく運用するためにはリリースの方法や品質面などで考慮すべき点も多く出てきますが、効果的な場面もあるので、もし興味を持ったら検討してみてください。
それぞれのブランチ戦略の意図する部分を理解することはできたでしょうか?他にもGitHub FlowやGitLab Flowなど、さまざまなブランチ戦略が提案されています。
ぜひ自チームで解決したい課題に置き換えて、選定してみてください。