こういった問題を解決するために「ブランチモデル」という管理法が提案されている。
メジャーなのが "git-flow" 。
"git-flow" という言葉は正確には Vincent Driessen 氏が提唱する
「A successful Git branching model」
(日本語訳 http://qiita.com/homhom44/items/9f13c646fa2619ae63d0)
というブランチモデルをサポートするツール(スクリプト)の名称を指しているが、ここでは「ブランチモデル」として整理する。
中央リポジトリ

まず中央リポジトリを準備し、各メンバーの作業はローカルリポジトリで作業する。
中央リポジトリは "origin" とする。リポジトリは自由に名前が付けれるが、gitを使ううえで馴染みが深い名称なので "origin" で統一する。
1人だけの作業であって中央リポジトリを準備し使うことにする。
(1人ならばネットワーク越しではなく、同一マシン上に準備しても良い)
各メンバーのローカルリポジトリを相互にリモートリポジトリとして追加して使っている。
これは、機能開発するうえで1人での単独開発だけではなく、機能の規模によりペアやチームを組んで機能開発にあたることがある。機能開発の途中段階において、中央リポジトリを使って共有するのではなく、各メンバー間でリモートリポジトリとして相互に指定して機能開発を進めることで、中央リポジトリに作業途中のコミットがあがることが避けられる。中央リポジトリはすっきりとした状態で保たれる。
(中央リポジトリ以外に、bareなリポジトリを準備できる場所を準備して、それをリモートリポジトリとして指定して共有して機能開発を進める。bareではないリポジトリを無理矢理に共有すると期待していない動作になるので注意)
定義されているブランチの種類
メインブランチ

中央リポジトリには、開発の最初から最後まで、恒久的に存在するブランチが2つ。
- master
"master" は gitブランチのデフォルトとしてのブランチ名だが、単にデフォルトだから使うのではなく、重要な役割をもつ名称として "master" が使われる。このブランチは常にリリース可能な安定版が反映される。
"master" ブランチに直接コミットすることはなく、マージを行うだけのブランチとなる。 - develop
普段の開発ではこのブランチが更新される。開発の最新状態となるブランチ。プロジェクト開始時リポジトリを新規作成したときに、まず "master" ブランチから "develop" ブランチを切る。"master" ブランチ同様に、このブランチに直接コミットすることはない。
サポートブランチ
機能開発、不具合修正、リリース準備など、目的を達成するために作成されるブランチ。役割が終わると削除される。各メンバーのローカルリポジトリ上で主に作業されるブランチとなる。
それぞれのブランチには特定の目的があり、名称や、どのブランチから分岐し、どのブランチをマージ対象としなければならないかという厳格なルールがある。
(名称はブランチモデルとして絶対的な定義があるわけではない。自由度があり、プロジェクトごとに決めることができる。)

- 機能ブランチ (feature branches) or トピックブランチ(topic branches)
機能開発や不具合修正などほとんどの作業で使う。ブランチ元 develop マージ先 develop ブランチ名ルール feature/? ブランチの存在期間 機能ブランチは実装が継続している間は存在し続ける。実装が完了し "develop" ブランチにマージされるか、仕様ドロップで打ち切られるまで存在する。
機能ブランチはメンバーのローカルリポジトリのみに存在し、中央リポジトリ "origin" には存在しない。
機能ブランチを新たに作成するには、"develop" ブランチから分岐する。$ git checkout -b myfeature develop
機能開発が完了したら "develop" ブランチへマージする。
マージするときは --no-ff オプションを指定し、fast-forwadマージが可能の場合であっても常にマージコミットを作成する。履歴に機能ブランチが存在したことの情報と、機能の追加のために行った作業をまとめて残しておける。$ git checkout develop :"develop" ブランチへ切り替える
$ git merge --no-ff feature/myapp :non-fast-forwardマージを指定
機能開発が終了し、"develop" ブランチへマージしたら、役目を終えたブランチは削除する。$ git branch -d feature/myapp

- リリースブランチ(release branches)
製品をリリースするために使う。リリーステストで見つかった不具合修正や、リリースバージョンを付けたり、リリースのための関連作業を行う。ブランチ元 develop マージ先 develop と master ブランチ名ルール release/? ブランチの存在期間 "develop" ブランチの状態が新しくリリースさせても良い状態になった時にブランチを切る。リリースが完全に出荷されるまでブランチは存在し続ける。
リリースブランチを切り、リリース作業はそのブランチで専念することで、"develop" ブランチはリリースを気にすることなく作業を進めることができる。タイミング悪く、もし、今からのリリースに含まれない機能を "develop" ブランチへマージしようと思うのであれば、リリースブランチが切られるまで待ってからマージすること。
リリースブランチを新たに作成するには、"develop" ブランチから分岐する。$ git checkout -b release/1.1 develop
リリース作業中に見つかった不具合は、リリースブランチに対して適用する。
これはリリース完了してから、まとめて "develop" ブランチへ反映するため。
リリースできる状態になったら、"master" ブランチへマージし、タグも設定する。$ git checkout master :"master" ブランチへ切り替える
$ git merge --no-ff release/1.1 :non-fast-forwardマージを指定
$ git tag -a 1.1 :注釈コメントも付ける
リリースブランチで修正した内容を "develop" ブランチへも反映する。このときコンフリクトが起こる可能性が高いので注意してマージする。$ git checkout develop :"develop" ブランチへ切り替える
$ git merge --no-ff release/1.1 :non-fast-forwardマージを指定
リリースが完了し、"master"・"develop" ブランチへのマージも完了したら、役目を終えたブランチは削除する。$ git branch -d release/1.1

- Hotfixブランチ(hotfix branches)
製品リリースした後で、重大な不具合が見つかり緊急対応が必要な場合に使う。次のリリースのためのブランチという意味でリリースブランチと似ているが、意図的に発生するものではない。ブランチ元 master マージ先 develop と master ブランチ名ルール hotfix/? ブランチの存在期間 リリース後に重大な不具合が見つかり、緊急で対策を行いたい場合にブランチを切る。次のリリースが完全に出荷されるまでブランチは存在し続ける。
"master" ブランチから分岐することで、"develop" ブランチの状況を気にせず、即座に緊急対応が可能。逆に担当者が緊急対応中でも他メンバーは "develop" ブランチで開発作業を継続できる。
不具合修正とリリースバージョンを付け、その他リリースを行うための関連作業を行うという点で、リリースブランチと同じ。
Hofixブランチは "master" ブランチから作成される。$ git checkout -b hotfix/1.2.1 master
リリースできる状態になったら、"master" ブランチへマージし、タグも設定する。$ git checkout master :"master" ブランチへ切り替える
$ git merge --no-ff hotfix/1.2.1 :non-fast-forwardマージを指定
$ git tag -a 1.2.1 :注釈コメントも付ける
Hofixブランチで修正した内容を "develop" ブランチへも反映する。
もし、このタイミングで進行中のリリースブランチがあれば、例外的にリリースブランチへマージする。これは、リリースブランチが完了すれば最終的に "develop" ブランチにも Hotfixブランチの不具合修正内容は反映されることになるから。ただしリリースブランチ完了まで待てない事情があれば、"develop" ブランチへマージしても問題はない。$ git checkout develop :"develop" ブランチへ切り替える
$ git merge --no-ff hotfix/1.2.1 :non-fast-forwardマージを指定
リリースが完了し、"master"・"develop" ブランチへのマージも完了したら、役目を終えたブランチは削除する。$ git branch -d hotfix/1.2.1

- (オプション)Supportブランチ(support branches)
必須ではないが、旧バージョンをサポートし続けなければいけない場合に使う。旧バージョンの保守とリリースを行う。ブランチ元 master マージ先 develop ブランチ名ルール support/? ブランチの存在期間 旧バージョンをサポートする必要が発生した場合にブランチを切る。以降はサポートが終了するまで、恒久的に存在する。
Supportブランチは "master" ブランチからタグを指定し作成する。合わせて Supportブランチ用の Hotfixブランチを作成する。$ git checkout -b support/1.x 1.2 :Supportブランチを作成し切り替える
$ git checkout -b hotfix/1.2.1
Hotfixブランチで不具合修正を行い、リリースできる状態になったら、Supportブランチへマージし、タグも設定する。$ git checkout support/1.x :Supportブランチへ切り替える
$ git merge --no-ff hotfix/1.2.1 :non-fast-forwardマージを指定
$ git tag -a 1.2.1 :注釈コメントも付ける
旧バージョンのサポート用リリースが完了したら、役目を終えた Hotfixブランチは削除する。$ git branch -d hotfix/1.2.1
混乱を避けるために、原則として、Supportブランチや、そこから分岐する Hotfixブランチを他のブランチへマージすることは避ける。
最新リリースに対しても急ぎ不具合修正を反映する場合は、新たにHotfixブランチを作成する。$ git checkout -b hotfix/2.0.1 master
(最新リリースに対して即時対応が必要なければ、"develop" ブランチから機能ブランチを分岐し、不具合修正として対応する。Hotfixブランチとは違うが対応の仕方は同じこと。)
リリースできる状態になったら、"master" ブランチと "develop" ブランチへマージし、タグも設定する。$ git checkout master :"master" ブランチへ切り替える
$ git merge --no-ff hotfix/2.0.1 :non-fast-forwardマージを指定
$ git tag -a 2.0.1 :注釈コメントも付ける
$ git checkout develop :"develop" ブランチへ切り替える
$ git merge --no-ff hotfix/2.0.1 :non-fast-forwardマージを指定
リリースが完了したら、役目を終えたブランチは削除する。$ git branch -d hotfix/2.0.1
git-flow インストール
ここではマニュアルでインストールしてみる(nvie版)。
(git flow wiki:Installing git-flow manually)
git-flow を github から clone する。リポジトリを用意する場所に移動してから実行。
$ cd ~/Downloads/gitflow
$ git clone --recursive git://github.com/nvie/gitflow.git
ツール(スクリプト)をインストール(コピー)する。
インストール先は、デフォルトは "/usr/local/bin"
$ sudo bash gitflow/contrib/gitflow-installer.sh
### gitflow no-make installer ### |
アンインストールする場合は、clone を実行したディレクトリから以下を実行する。
$ sudo bash gitflow/contrib/gitflow-installer.sh uninstall
### gitflow no-make installer ### |
Ubuntuでは、apt管理から git-flow をインストールするとAVH版がインストールされる。
$ sudo apt-get install git-flow
基本は同じだが、こちらは機能が拡張されている。大は小を兼ねるの方針でAVH版を入れておけば問題ない。ここでは話が広がり過ぎるのでベースとなるnvie版を入れた。git-flow を使ってみる
git コマンドの代わりに、git flow コマンドを使う。git コマンドもいつも通りに使える。git flow を使うことで、git-flow ルールを強制することができる。
リポジトリの初期化
各ブランチとタグの名称を指定するが、基本的にデフォルトのままでよいので、そのままEnterキーを押して進めれば良い。
$ git flow init
Initialized empty Git repository in ********************/.git/ |
ブランチの状態を確認してみる。
$ git branch |
"master" ブランチと "develop" ブランチが作成され、"develop" ブランチがチェックアウトされた状態となっている。
もし、初期化を修正したかったら、-f オプションを使う。
$ git flow init -f
これで再度初期設定が実行される。
中央リポジトリへ反映
中央リポジトリ となるリモートリポジトリを準備する。
ローカルリポジトリに、中央リポジトリ "origin" を設定して、プッシュする。
$ git remote add origin <リモートリポジトリのアドレス>
$ git push --all
ブランチの状態を確認してみる。
$ git branch -a |
リモート追跡ブランチも設定できた。
各メンバーの準備
中央リポジトリからクローンする。
$ git clone <リモートリポジトリのアドレス>
単にクローンしただけななおで、まだ "git-flow" の設定が紐づけられていない。
各メンバーのマシンにおいても初期設定を行う。これも git flow init でいける。注意するのは、プロジェクト内で用いるブランチ名はそろえておくこと。
$ git flow init
Initialized empty Git repository in ********************/.git/ |
追跡ブランチを確認してみる。
$ git branch -vv |
ローカルリポジトリの各ブランチにも、ちゃんと上流ブランチが設定されている。これで "git-flow" を使う準備ができた。
作業で使うブランチの種類は以下。
- feature :機能ブランチ
- release :リリースブランチ
- hotfix :Hotfixブランチ
- support :Supportブランチ
作業の開始
どのブランチでも基本的な流れは同じ。例として、機能ブランチを作成する。
$ git flow feature start app1
$ git branch |
"feature/app1" ブランチが作成され、チェックアウトされた状態になった。
このブランチで作業を行う。
ブランチ操作は、通常のgitコマンドを使えばよい。
作業の終了
作業が終了したらマージする。git-flow に限ったことではないが、マージする前にスカッシュやリベースでコミットの内容を整理しておくと後から履歴を見返したときにわかり易くなるのでおススメ。
$ git flow feature finish app1
マージコミットメッセージを入力するエディタが起動するので、メッセージを入れる。
ブランチを確認してみる。
$ git branch |
"feature/app1" ブランチが削除され、"develop" ブランチがチェックアウトされた状態になった。
develop ブランチを中央リポジトリへ反映
develop ブランチを更新したので、中央リポジトリへ反映する。
$ git push --all
基本的に、作業開始し、作業終了でマージし、中央リポジトリへプッシュするというのが流れ。
コンフリクトなど問題が発生した場合は、git-flow のスクリプトも止まるので、その場合は残りは手作業となる。git-flow のモデルを理解していないと問題対処後に何をすべきかがわからないので、ブランチモデルを知らなくても使えるというツールではないことに注意。
まとめ
"git-flow" で理解・管理しておけば多くの場面で、ブランチ管理の混乱は避けられ、途中参加したメンバーもスムーズに作業に集中できると思う。また "git-flow" と言っても、上で記述したブランチ以外にも、機能ブランチとは分けて、bugfixブランチを用意する場合もある。このシンプルな形で進めればいいのだけど、このモデルをベースにして、うまくやってくれ、ということだと思う。多少の足し引きがあっても、考え方が沿っていれば理解は早い。後はプロジェクト、チームに沿ったやり方を毎回、模索するしかないと思う。
gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元



