2017年08月06日

git ブランチモデル git-flow

git のブランチは好きに使って効率よく作業すればいいのだが、好き勝手やり過ぎて効果的に使えなくなると意味がない。特にチームで使うとなると秩序が必要となる。また様々なチームを渡り歩いて作業するようなことになると、行く先々でルールが異なると、ローカルルールに従うことだけで苦労する。

こういった問題を解決するために「ブランチモデル」という管理法が提案されている。
メジャーなのが "git-flow" 。

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





中央リポジトリ


git-flow02.png
まず中央リポジトリを準備し、各メンバーの作業はローカルリポジトリで作業する。
中央リポジトリは "origin" とする。リポジトリは自由に名前が付けれるが、gitを使ううえで馴染みが深い名称なので "origin" で統一する。
1人だけの作業であって中央リポジトリを準備し使うことにする。
(1人ならばネットワーク越しではなく、同一マシン上に準備しても良い)


各メンバーのローカルリポジトリを相互にリモートリポジトリとして追加して使っている。
これは、機能開発するうえで1人での単独開発だけではなく、機能の規模によりペアやチームを組んで機能開発にあたることがある。機能開発の途中段階において、中央リポジトリを使って共有するのではなく、各メンバー間でリモートリポジトリとして相互に指定して機能開発を進めることで、中央リポジトリに作業途中のコミットがあがることが避けられる。中央リポジトリはすっきりとした状態で保たれる。
(中央リポジトリ以外に、bareなリポジトリを準備できる場所を準備して、それをリモートリポジトリとして指定して共有して機能開発を進める。bareではないリポジトリを無理矢理に共有すると期待していない動作になるので注意)




定義されているブランチの種類


メインブランチ


git-flow01.png
中央リポジトリには、開発の最初から最後まで、恒久的に存在するブランチが2つ。
  • master
    "master" は gitブランチのデフォルトとしてのブランチ名だが、単にデフォルトだから使うのではなく、重要な役割をもつ名称として "master" が使われる。このブランチは常にリリース可能な安定版が反映される。
    "master" ブランチに直接コミットすることはなく、マージを行うだけのブランチとなる。
  • develop
    普段の開発ではこのブランチが更新される。開発の最新状態となるブランチ。プロジェクト開始時リポジトリを新規作成したときに、まず "master" ブランチから "develop" ブランチを切る。"master" ブランチ同様に、このブランチに直接コミットすることはない。






サポートブランチ


機能開発、不具合修正、リリース準備など、目的を達成するために作成されるブランチ。役割が終わると削除される。各メンバーのローカルリポジトリ上で主に作業されるブランチとなる。
それぞれのブランチには特定の目的があり、名称や、どのブランチから分岐し、どのブランチをマージ対象としなければならないかという厳格なルールがある。
(名称はブランチモデルとして絶対的な定義があるわけではない。自由度があり、プロジェクトごとに決めることができる。)




git-flow03.png
  • 機能ブランチ (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




git-flow04.png
  • リリースブランチ(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




git-flow05.png
  • 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




git-flow06.png
  • (オプション)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 ###
Installing git-flow to /usr/local/bin
Using existing repo: gitflow
Submodules look up to date
'gitflow/git-flow' -> '/usr/local/bin/git-flow'
'gitflow/git-flow-init' -> '/usr/local/bin/git-flow-init'
'gitflow/git-flow-feature' -> '/usr/local/bin/git-flow-feature'
'gitflow/git-flow-hotfix' -> '/usr/local/bin/git-flow-hotfix'
'gitflow/git-flow-release' -> '/usr/local/bin/git-flow-release'
'gitflow/git-flow-support' -> '/usr/local/bin/git-flow-support'
'gitflow/git-flow-version' -> '/usr/local/bin/git-flow-version'
'gitflow/gitflow-common' -> '/usr/local/bin/gitflow-common'
'gitflow/gitflow-shFlags' -> '/usr/local/bin/gitflow-shFlags'




アンインストールする場合は、clone を実行したディレクトリから以下を実行する。

$ sudo bash gitflow/contrib/gitflow-installer.sh uninstall

### gitflow no-make installer ###
Uninstalling git-flow from /usr/local/bin
rm -vf /usr/local/bin/git-flow-init
'/usr/local/bin/git-flow-init' を削除しました
rm -vf /usr/local/bin/git-flow-feature
'/usr/local/bin/git-flow-feature' を削除しました
rm -vf /usr/local/bin/git-flow-hotfix
'/usr/local/bin/git-flow-hotfix' を削除しました
rm -vf /usr/local/bin/git-flow-release
'/usr/local/bin/git-flow-release' を削除しました
rm -vf /usr/local/bin/git-flow-support
'/usr/local/bin/git-flow-support' を削除しました
rm -vf /usr/local/bin/git-flow-version
'/usr/local/bin/git-flow-version' を削除しました
rm -vf /usr/local/bin/gitflow-common
'/usr/local/bin/gitflow-common' を削除しました
rm -vf /usr/local/bin/gitflow-shFlags
'/usr/local/bin/gitflow-shFlags' を削除しました
rm -vf /usr/local/bin/git-flow
'/usr/local/bin/git-flow' を削除しました






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/
No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []



ブランチの状態を確認してみる。
$ git branch
* develop
master

"master" ブランチと "develop" ブランチが作成され、"develop" ブランチがチェックアウトされた状態となっている。


もし、初期化を修正したかったら、-f オプションを使う。

$ git flow init -f


これで再度初期設定が実行される。



中央リポジトリへ反映


中央リポジトリ となるリモートリポジトリを準備する。
ローカルリポジトリに、中央リポジトリ "origin" を設定して、プッシュする。

$ git remote add origin <リモートリポジトリのアドレス>
$ git push --all


ブランチの状態を確認してみる。
$ git branch -a
* develop
master
remotes/origin/develop
remotes/origin/master

リモート追跡ブランチも設定できた。




各メンバーの準備


中央リポジトリからクローンする。

$ git clone <リモートリポジトリのアドレス>


単にクローンしただけななおで、まだ "git-flow" の設定が紐づけられていない。
各メンバーのマシンにおいても初期設定を行う。これも git flow init でいける。注意するのは、プロジェクト内で用いるブランチ名はそろえておくこと。

$ git flow init

Initialized empty Git repository in ********************/.git/
No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []


追跡ブランチを確認してみる。
$ git branch -vv
* develop 9790466 [origin/develop] Initial commit
master 9790466 [origin/master] Initial commit

ローカルリポジトリの各ブランチにも、ちゃんと上流ブランチが設定されている。これで "git-flow" を使う準備ができた。


作業で使うブランチの種類は以下。
  • feature :機能ブランチ
  • release :リリースブランチ
  • hotfix :Hotfixブランチ
  • support :Supportブランチ

作業の開始


どのブランチでも基本的な流れは同じ。例として、機能ブランチを作成する。

$ git flow feature start app1

$ git branch
develop
* feature/app1
master

"feature/app1" ブランチが作成され、チェックアウトされた状態になった。


このブランチで作業を行う。
ブランチ操作は、通常のgitコマンドを使えばよい。



作業の終了


作業が終了したらマージする。git-flow に限ったことではないが、マージする前にスカッシュやリベースでコミットの内容を整理しておくと後から履歴を見返したときにわかり易くなるのでおススメ。

$ git flow feature finish app1


マージコミットメッセージを入力するエディタが起動するので、メッセージを入れる。

ブランチを確認してみる。
$ git branch
* develop
master

"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 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする